3

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

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

4

6 回答 6

3

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

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

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

在多看MSDN 文档ThreadState之后,您应该能够使用该属性来区分外部中止的线程。这应该设置为ThreadState.Aborted线程响应 Abort() 调用时。但是,除非您可以控制正在运行的线程代码,否则我认为您无法区分刚刚退出其 main 方法的线程与以异常终止的线程。

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

于 2009-06-16T15:04:43.640 回答
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!");
        }
    }
}


于 2009-06-16T15:33:00.120 回答
1

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

于 2009-06-16T15:02:03.613 回答
1

假设主线程需要等待工作线程成功完成,我一般使用ManualResetEvent。或者,对于多个工作线程,来自 Parallels Extensions 的新 CountDownEvent,就像这样

于 2009-06-16T15:16:24.270 回答
0

我使用 aCancellationTokenSource要求线程优雅地退出。

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

如果exitedProperly==false,我将错误推送到日志中。

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

于 2015-12-16T22:30:19.167 回答
-1

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

于 2009-06-16T14:52:36.613 回答