3

ThreadStateの MSDN ドキュメントによると、Stopped 状態には、スレッドの終了、またはスレッドの中止という 2 つの方法のいずれかによって入ることができます。

スレッドが正常に終了して Stopped 状態になったかどうかを判断するメカニズムはありますか? ありがとう!

4

6 に答える 6

3

コードを監視するスレッドはありますか? その場合は、すべてをクラスにラップし、終了時にイベントを発生させるか、WaitHandle (私は ManualResetEvent を使用します) を使用して完了を知らせることができます。-- バックグラウンド ロジックを完全にカプセル化します。このカプセル化を使用して、例外をキャプチャし、イベントを発生させることもできます。

このようなもの:


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

namespace BackgroundWorker
{
    public class BackgroundWorker
    {
        /// 
        /// Raised when the task completes (you could enhance this event to return state in the event args)
        /// 
        public event EventHandler TaskCompleted;

        /// 
        /// Raised if an unhandled exception is thrown by the background worker
        /// 
        public event EventHandler BackgroundError;

        private ThreadStart BackgroundTask;
        private readonly ManualResetEvent WaitEvent = new ManualResetEvent(false);

        /// 
        /// ThreadStart is the delegate that  you want to run on your background thread.
        /// 
        /// 
        public BackgroundWorker(ThreadStart backgroundTask)
        {
            this.BackgroundTask = backgroundTask;
        }

        private Thread BackgroundThread;

        /// 
        /// Starts the background task
        /// 
        public void Start()
        {
            this.BackgroundThread = new Thread(this.ThreadTask);
            this.BackgroundThread.Start();

        }

        private void ThreadTask()
        {
            // the task that actually runs on the thread
            try
            {
                this.BackgroundTask();
                // completed only fires on successful completion
                this.OnTaskCompleted(); 
            }
            catch (Exception e)
            {
                this.OnError(e);
            }
            finally
            {
                // signal thread exit (unblock the wait method)
                this.WaitEvent.Set();
            }

        }

        private void OnTaskCompleted()
        {
            if (this.TaskCompleted != null)
                this.TaskCompleted(this, EventArgs.Empty);
        }

        private void OnError(Exception e)
        {
            if (this.BackgroundError != null)
                this.BackgroundError(this, new BackgroundWorkerErrorEventArgs(e));
        }

        /// 
        /// Blocks until the task either completes or errrors out
        /// returns false if the wait timed out.
        /// 
        /// Timeout in milliseconds, -1 for infinite
        /// 
        public bool Wait(int timeout)
        {
            return this.WaitEvent.WaitOne(timeout);
        }

    }


    public class BackgroundWorkerErrorEventArgs : System.EventArgs
    {
        public BackgroundWorkerErrorEventArgs(Exception error) { this.Error = error; }
        public Exception Error;
    }

}

注: Start が 2 回呼び出されないようにするためのコードが必要です。また、状態をスレッドに渡すための状態プロパティを追加することもできます。

このクラスの使用方法を示すコンソール アプリを次に示します。


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

namespace BackgroundWorker
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Test 1");
            BackgroundWorker worker = new BackgroundWorker(BackgroundWork);
            worker.TaskCompleted += new EventHandler(worker_TaskCompleted);
            worker.BackgroundError += new EventHandler(worker_BackgroundError);
            worker.Start();
            worker.Wait(-1);

            Console.WriteLine("Test 2");
            Console.WriteLine();

            // error case
            worker = new BackgroundWorker(BackgroundWorkWithError);
            worker.TaskCompleted += new EventHandler(worker_TaskCompleted);
            worker.BackgroundError += new EventHandler(worker_BackgroundError);
            worker.Start();
            worker.Wait(-1);

            Console.ReadLine();
        }

        static void worker_BackgroundError(object sender, BackgroundWorkerErrorEventArgs e)
        {
            Console.WriteLine("Exception: " + e.Error.Message);
        }

        private static void BackgroundWorkWithError()
        {
            throw new Exception("Foo");
        }

        static void worker_TaskCompleted(object sender, EventArgs e)
        {
            Console.WriteLine("Completed");
        }

        private static void BackgroundWork()
        {
            Console.WriteLine("Hello!");
        }
    }
}


于 2009-06-16T15:33:00.120 に答える
3

スレッドは、いくつかの方法で Stopped 状態に到達できます。

  • メインメソッドはエラーなしで終了できます。
  • スレッドでキャッチされない例外により、スレッドが終了する可能性があります。
  • 別のスレッドが Thread.Abort() を呼び出すと、そのスレッドで ThreadAbortException がスローされます。

3 つの状態すべてを区別しようとしているかどうかはわかりませんが、スレッドが正常に完了したかどうかだけに関心がある場合は、何らかの共有データ構造を使用することをお勧めします (同期辞書が機能します)。スレッドのメイン ループは、終了時に更新されます。この共有ディクショナリでは、ThreadName プロパティをキーとして使用できます。終了状態に関心のある他のスレッドは、このディクショナリから読み取り、スレッドの最終ステータスを判断できます。

MSDN ドキュメントをもう少し調べた後、ThreadStateプロパティを使用して外部で中止されたスレッドを区別できるはずです。これはThreadState.Aborted、スレッドが Abort() 呼び出しに応答するときに設定する必要があります。ただし、実行されるスレッドコードを制御できない限り、メインメソッドを終了したばかりのスレッドと例外で終了したスレッドを区別できないと思います。

ただし、スレッドを開始するコードを制御する場合は、メイン スレッド ロジックを実行するコードを内部的に呼び出す独自のメソッドをいつでも置き換えることができ、そこに例外検出を挿入できます (前述のとおり)。

于 2009-06-16T15:04:43.640 に答える
1

BackgroundWorker クラスを見たいと思うかもしれません。スレッドが完了したときの汎用イベント ハンドラーがあります。そこでは、スレッドがエラーのために完了したか、キャンセルされたか、または正常に終了したかを確認できます。

于 2009-06-16T15:02:03.613 に答える
1

ワーカー スレッドが正常に完了するまでメイン スレッドが待機する必要があると仮定すると、通常は ManualResetEvent を使用します。または、複数のワーカー スレッドの場合は、Parallels Extensions からの新しい CountDownEvent などです

于 2009-06-16T15:16:24.270 に答える
-1

スレッドは、Thread.Abort() を呼び出すことによってのみ中止できます。その結果、ThreadAbortException が発生します。そのため、例外処理を通じて、通常の終了と中止された終了を判断できるはずです。

于 2009-06-16T14:52:36.613 に答える