2016-06-16 13 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の出力を参照してください、私はテストのスレッドオブジェクトを検査するとき、私はとThreadStatus = TheadStatus.Running、IsAliveのはまだ本当であることがわかります。この例を考えてみましょう。どうしてこれなの?私は、スレッドが本当に完全であることを検出したいと思いますが、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.Start()'を実行する前に、 't.Name =" TestThread ";'を実行してください。また、最近のC#の 'Thread'クラスで直接作業することは頻繁ではありません。現代のC#では、通常はそれをラップする' Task'抽象で作業します。最後に、 'Console.Log(' from、 'Log'メソッドは' System.Console'クラスに組み込まれていません。 –

+0

これは非常にトリミングされた例ですが、私の実際の世界ではこのスレッド(メインスレッドに加えて)だけがありますので、私が見ている正しいスレッドであることがわかります。私はタスク抽象化を認識していませんでした。私はそれをチェックしますが、私はまだこれをよりよく理解したいと思っています。 – dmarra

+0

またConsole.Logは存在しません。私はその例を汲み出したときに.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 block forever ...タイムアウトを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がfalseです。

+0

あなたは正しいです。私のテスト方法は絶対に欠陥があります。私は本質的にあなたのコメントを読んだ後と同じことをやった、と私は同じ結果を得た。私の実際の使用シナリオで何らかの理由で、私のスレッドは、スレッド関数が返った後に完了しません。私はこれを再現する最小限の例をどうやって作ることができるか考えようとしています... – dmarra

0

だから、私の問題は私の伐採方法がそうのようなUIスレッド関数を呼び出したということであったことが判明:呼び出し()ラインで

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); 
      } 
     } 

、スレッドは永久にハングアップするでしょう。解決策は、代わりにBeginInvoke()で置き換えることでした。

編集:また、私の例は/これはかなり悪いです。基本的なレベルでスレッドを理解していないと思っていて、私の例では十分だったはずです。うまくいけば、誰かがこれを考えても同じ理由でこのソリューションを試すことができます。

関連する問題