如何判断一个线程是否已成功退出?

时间:2009-06-16 14:47:28

标签: c# multithreading thread-state

根据MSDN Documentation for ThreadState,可以通过以下两种方式之一进入Stopped状态:线程退出或线程被中止。

是否有一些机制通过正常退出来判断某个线程是否已进入Stopped状态?谢谢!

6 个答案:

答案 0 :(得分:3)

线程可以通过多种方式达到Stopped状态:

  • 它的主要方法可以在没有任何错误的情况下退出。
  • 线程上未捕获的异常可以终止它。
  • 另一个线程可以调用Thread.Abort(),这会导致在该线程上抛出ThreadAbortException。

我不知道你是否想要区分这三种状态,但如果你真正感兴趣的是线程是否成功完成,我会建议使用某种类型的共享数据结构(同步字典会工作)线程的主循环在终止时更新。您可以使用ThreadName属性作为此共享字典中的键。对终止状态感兴趣的其他线程可以从该字典中读取以确定线程的最终状态。

MSDN documentation查看更多内容后,您应该能够使用ThreadState属性区分外部中止的线程。当线程响应Abort()调用时,应将此值设置为ThreadState.Aborted。但是,除非您控制运行的线程代码,否则我认为您不能区分刚退出其主方法的线程与以异常终止的线程。

但请记住,如果您控制启动线程的代码,您始终可以替换自己的方法,该方法在内部调用运行主线程逻辑的代码并注入异常检测(因为我如上所述)那里。

答案 1 :(得分: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被调用两次,并且您可能希望添加一个state属性以将状态传递给您的线程。

这是一个控制台应用程序,演示了如何使用此类:


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


答案 2 :(得分:1)

您可能希望查看BackgroundWorker类。它有一个通用事件处理程序,用于线程完成时。在那里,您可以检查线程是否由于错误而完成,因为它已被取消或因为它已成功完成。

答案 3 :(得分:1)

假设主线程需要等待工作线程成功完成,我通常使用ManualResetEvent。或者,对于多个工作线程,来自Parallels Extensions的新CountDownEvent,如so

答案 4 :(得分:0)

我使用CancellationTokenSource让线程正常退出。

然后我使用等待线程退出的var exitedProperly = _thread.Join(TimeSpan.FromSeconds(10);

如果exitedProperly==false,我会将错误输入日志。

我主要在Dispose()函数中使用此模式时,我正在尝试清理我创建的任何线程。

答案 5 :(得分:-1)

线程只能通过调用Thread.Abort()来中止,这会导致ThreadAbortException,因此通过异常处理,您应该能够确定正常退出与中止退出。