2016-06-16 6 views
0

У меня с этим много проблем. Рассмотрим следующий пример:Как проверить, что поток завершен?

public class Test { 
    Thread t; 

    public Test() { 
     t = new Thread(ThreadFunction); 
    } 

    public void Start() { 
     t.Start(); 
    } 

    private void ThreadFunction() { 
     Thread.Sleep(5000); 
     Console.WriteLine("Function Complete"); 
    }  
} 


public static class Main { 
    public Main() { 
     Test test = new Test(); 
     test.Start(); 

     // sleep longer than my worker so it finishes 
     Thread.Sleep(10000); 

     // a place to place a breakpoint 
     bool breakPointHere = true; 
    }   
} 

Теперь я вижу выход console.log, но когда я инспектировать объект потока Test, я вижу, что IsAlive по-прежнему верно, и ThreadStatus = TheadStatus.Running. Почему это? Я хочу обнаружить, что поток действительно завершен, но я смущен тем, как его можно считать запущенным, если ThreadFunction() завершает?

EDIT 2:

я, наконец, разыскали причину, обновления кода, и я собираюсь ответить на мой собственный вопрос

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 


namespace ConsoleApplication1 { 
    public abstract class Worker { 
     protected bool shutdown; 
     protected Thread t; 

     private bool _isStopped = true; 
     public bool IsStopped { 
      get { 
       return t.ThreadState == ThreadState.Stopped; 
      } 
     } 

     private bool _isPaused = false; 
     public bool IsPaused { 
      get { 
       return _isPaused; 
      } 
     } 

     private string stringRepresentation; 

     public Worker() { 
      t = new Thread(ThreadFunction); 
      stringRepresentation = "Thread id:" + t.ManagedThreadId; 
      t.Name = stringRepresentation; 
     } 


     public void Start() { 
      OnBeforeThreadStart(); 
      t.Start(); 
     } 

     public void ScheduleStop() { 
      shutdown = true; 
     } 

     public void SchedulePause() { 
      OnPauseRequest(); 
      _isPaused = true; 
     } 

     public void Unpause() { 
      _isPaused = false; 
     } 

     public void ForceStop() { 
      t.Abort(); 
     } 


     /// <summary> 
     /// The main thread loop. 
     /// </summary> 
     private void ThreadFunction() { 
      OnThreadStart(); 
      while (!shutdown) { 
       if (!IsPaused) { 
        if (!OnLoop()) { 
         break; 
        } 
       } 
       Thread.Sleep(1000); 
      } 
      OnShutdown(); 
     } 

     public abstract void OnBeforeThreadStart(); 
     public abstract void OnThreadStart(); 
     public abstract bool OnLoop(); 
     public abstract void OnShutdown(); 
     public abstract void OnPauseRequest(); 


     public override string ToString() { 
      return stringRepresentation; 
     } 
    } 


    public class Test : Worker { 
     public override void OnBeforeThreadStart() { 
      Log.WriteLine(this + ": Thread about to be started..."); 
     } 

     public override void OnThreadStart() { 
      Log.WriteLine(this + ": Thread Started!"); 
     } 

     public override bool OnLoop() { 
      Log.WriteLine(this + ": I am doing the things..."); 
      return true; 
     } 

     public override void OnShutdown() { 
      Log.WriteLine(this + ": Shutting down!"); 
     } 

     public override void OnPauseRequest() {    
     } 
    } 



public static class Log { 
    public delegate void LogDelegate(string text, string eventTime, Severity severity); 

    public static event LogDelegate OnWriteLine; 

    private static Queue<string> _pendingFileWrites = new Queue<string>(); 


    public enum Severity { 
     Info, 
     Warning, 
     Error 
    } 


    public static void WriteLine(object line, Severity severity = Severity.Info) { 
     string eventTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); 
     string formatted = "[" + eventTime + "]: " + line; 
     Console.WriteLine(formatted); 

     lock (_pendingFileWrites) { 
      _pendingFileWrites.Enqueue(formatted); 
     } 

     if (OnWriteLine != null) { 
      // this is the offending line: 
      OnWriteLine.Invoke((string)line, eventTime, severity); 
     } 
    } 


    public static void WriteToFile(string path) { 
     lock(_pendingFileWrites) { 
      StreamWriter sw = File.AppendText(path);   
      while(_pendingFileWrites.Count > 0) { 
       sw.WriteLine(
        _pendingFileWrites.Dequeue() 
       ); 
      } 
      sw.Close(); 
     } 
    } 
} 



    class Program { 
     static void Main(string[] args) { 
      List<Test> tests = new List<Test>(); 
      for(int i = 0; i < 10; i++) { 
       Test test = new Test(); 
       test.Start(); 
       tests.Add(test); 
      } 

      // sleep a little bit so they do the things 
      Thread.Sleep(10000); 

      foreach (Test test in tests) { 
       test.ScheduleStop(); 
      } 

      bool allStopped; 
      do { 
       allStopped = true; 
       foreach (Test test in tests) { 
        if (!test.IsStopped) { 
         allStopped = false; 
         break; 
        } 
       } 
      } while (!allStopped); 

      Console.WriteLine("Done!"); 

      // a place to place a breakpoint 
      bool breakPointHere = true; 
     } 
    } 
} 
+0

Вы уверены, что искали подходящую тему? Сделайте 't.Name =" TestThread ";' перед тем, как вы сделаете 't.Start()', чтобы помочь вам однозначно идентифицировать поток. Кроме того, не так часто работать непосредственно с классом «Thread» в современном C#, в современном C# вы обычно работаете с абстракцией 'Task', которая ее обертывает. Наконец, где вы получаете 'Console.Log (' from, метод 'Log' не является частью встроенного класса' System.Console'. –

+0

Это очень урезанный пример, но в моем реальном мире позаботьтесь только об этой теме (в дополнение к основной теме), поэтому я точно знаю, что это правильный поток, на который я смотрю. Однако я не знал об абстракции задачи. Я проверю это, но я все еще хочу понять это лучше. – dmarra

+0

Также Console.Log doens; t существует. Я смешал мой .Net и Unity C#, когда я выкачал этот пример: P. Это Console.WriteLine() – dmarra

ответ

1

ли вам действительно нужно спать, чтобы ждать вашего потока заканчивать? Если вы этого не сделаете, лучше и более надежное решение будет использовать Thread.Join()

public static class Main { 
    public Main() { 
     Test test = new Test(); 
     test.Start(); 

     test.Join(); // Waits for test to complete 
     bool breakPointHere = true; 
    }   
} 
+0

И даже создать таймер можно, так что он выиграл 't заблокировать навсегда ... Если вы используете тайм-аут 0, вы получаете тестовый метод для проверки, если он все еще работает. Я не думаю, что полезно добавлять ответы на similair, вот почему +1. –

+0

На самом деле это не вопрос, я ценю отзывы, но это выходит за рамки. Я попытался сделать очень простой пример. В реальном мире это не так. Пример плох, и я пытаюсь сформулировать тот, который представляет собой настоящую проблему. Я думал, что просто не понимаю эти свойства, но, видимо, у меня есть реальная ошибка. – dmarra

2

Я думаю, что ваше оригинальное тестирование, которое приведет вас верить .IsAlive бы быть правда имела некоторый недостаток в этом, я отлажен вашу программе в вашем задайте следующий вопрос, чтобы сделать его компиляцией и иметь возможность видеть, какой поток он создал.

public class Program 
{ 
    public class Test 
    { 
     Thread t; 

     public Test() 
     { 
      t = new Thread(ThreadFunction); 
      t.Name = "TestThread"; 
     } 

     public void Start() 
     { 
      t.Start(); 
     } 

     private void ThreadFunction() 
     { 
      Thread.Sleep(5000); 
      Console.WriteLine("Function Complete"); 
     } 
    } 


    public static void Main() 
    { 
     Test test = new Test(); 
     test.Start(); 

     // sleep longer than my worker so it finishes 
     Thread.Sleep(10000); 

     // a place to place a breakpoint 
     bool breakPointHere = true; 
    } 
} 

вот скриншот из запущенных потоков внутри ThreadFunction

enter image description here

Вот скриншот с конца программы

enter image description here

Обратите внимание, что есть нет потока TestThread.

Вот скриншот из окна местных жителей

enter image description here

IsAlive является ложным.

+0

Вы правы; мой метод тестирования абсолютно ошибочен. Я сделал то же самое, что и после прочтения вашего комментария, и получил тот же результат. По какой-то причине в моем сценарии использования в реальном мире мой поток не завершается после возврата функции потока. Я пытаюсь думать о том, как я могу сделать минимальный пример, который воспроизводит это ... – dmarra

0

Так получается, что моя проблема в том, что мой метод регистрации был вызов функции потока пользовательского интерфейса следующим образом:

private void LogToForm(object line, string eventTime, Log.Severity severity) { 
      if (dataGridView_LogInfo.InvokeRequired) { 
       dataGridView_LogInfo.Invoke (
        new Action<object, string, Log.Severity>(LogtoFormCallback), 
        new object[] { line, eventTime, severity } 
       ); 

      } else { 
       LogtoFormCallback(line, eventTime, severity); 
      } 
     } 

На линии Invoke(), поток будет висеть вечно. Вместо этого было заменено на BeginInvoke().

EDIT: Кроме того, мой пример был/довольно беден для этого. Я думал, что я не понимаю темы на фундаментальном уровне и что моих примеров было бы достаточно. Надеюсь, что кто-то поймет это, хотя и имеет ту же самую причину, и может попробовать это решение.

Смежные вопросы