在多线程开发中,开发人员经常会碰到如何取消工作线程的问题,一般我们不建议使用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;
}
}
}