在多线程开发中,开发人员经常会碰到如何取消工作线程的问题,一般我们不建议使用Thread.Abort()来终止线程,MSDN中Thread.Abort方法的说明:“在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。调用此方法通常会终止线程。” 所以结束线程最好是让线程主动退出,可以通过变量、事件等方式通知线程。
以下代码是从书本上看到,非常好的解决了如何关闭工作线程的问题:
public class WorkerThread : IDisposable { ManualResetEvent m_ThreadHandle; Thread m_ThreadObj; bool m_EndLoop; Mutex m_EndLoopMutex; public WorkerThread() { m_EndLoop = false; m_ThreadObj = null; m_EndLoopMutex = new Mutex(); m_ThreadHandle = new ManualResetEvent(false); m_ThreadObj = new Thread(Run); Name = "Worker Thread"; } public WorkerThread(bool autoStart) : this() { if (autoStart) { Start(); } } public void Start() { Debug.Assert(m_ThreadObj != null); Debug.Assert(m_ThreadObj.IsAlive == false); //m_ThreadObj.Start(); } void Run() { try { int i = 0; while (EndLoop == false) { Trace.WriteLine(string.Format("THread is alive, Counter is {0}", i)); i++; } } finally { m_ThreadHandle.Set(); } } public void Dispose() { Kill(); } public void Kill() { Debug.Assert(m_ThreadObj != null); if(IsAlive == false) { return; } EndLoop = true; Join(); m_EndLoopMutex.Close(); m_ThreadHandle.Close(); } public void Join() { Join(Timeout.Infinite); } public bool Join(int millisecondsTimeout) { TimeSpan timeout = TimeSpan.FromMilliseconds(millisecondsTimeout); return Join(timeout); } public bool Join(TimeSpan timeout) { Debug.Assert(m_ThreadObj != null); if (IsAlive == false) { return true; } Debug.Assert(Thread.CurrentThread.ManagedThreadId != m_ThreadObj.ManagedThreadId); return m_ThreadObj.Join(timeout); } public string Name { get { return m_ThreadObj.Name; } set { m_ThreadObj.Name = value; } } public bool IsAlive { get { Debug.Assert(m_ThreadObj != null); bool handleSignaled = m_ThreadHandle.WaitOne(0, true);
//如果代码已经执行完毕,但工作线程的IsAlive仍为true,循环等待 while(handleSignaled == m_ThreadObj.IsAlive) { Thread.Sleep(0); } return m_ThreadObj.IsAlive; } } public override int GetHashCode() { return m_ThreadObj.GetHashCode(); } public override bool Equals(object obj) { return m_ThreadObj.Equals(obj); } public int ManagedThreadId { get { return m_ThreadObj.ManagedThreadId; } } public Thread Thread { get { return m_ThreadObj; } } protected bool EndLoop { set { m_EndLoopMutex.WaitOne(); m_EndLoop = value; m_EndLoopMutex.ReleaseMutex(); } get { bool result = false; m_EndLoopMutex.WaitOne(); result = m_EndLoop; m_EndLoopMutex.ReleaseMutex(); return result; } } public WaitHandle Handle { get { return m_ThreadHandle; } } }