千万不要使用Thread.Suspend
。它的主要问题是99%的情况下,当您暂停线程时,您无法知道该线程正在做什么。如果该线程持有锁,则易于陷入死锁等问题。请记住,您调用的代码可能在后台获取/释放锁。Win32有类似的API:SuspendThread
和ResumeThread
。以下关于SuspendThread
的文档概述了API的危险性:
http://msdn.microsoft.com/en-us/library/ms686345(VS.85).aspx
此函数主要供调试器使用。不建议将其用于线程同步。 在拥有同步对象(例如互斥体或临界区)的线程上调用SuspendThread可能会导致死锁,如果调用线程尝试获取由挂起的线程拥有的同步对象。为避免此情况,应用程序中的线程(非调试器)应发出信号以使其他线程暂停自身。目标线程必须设计成监视此信号并适当地响应。
永久暂停线程的正确方法是使用ManualResetEvent
。线程很可能正在循环执行某些工作。暂停线程的最简单方法是使线程在每个迭代中“检查”事件,例如:
while (true)
{
_suspendEvent.WaitOne(Timeout.Infinite);
}
你可以指定一个无限超时时间,这样当事件没有被触发时,线程会一直阻塞,直到事件被触发,此时线程将在离开的地方继续执行。
创建事件的方式如下:
ManualResetEvent _suspendEvent = new ManualResetEvent(true);
true
参数表示在事件开始时处于有信号状态。
当您想要暂停线程时,请执行以下操作:
_suspendEvent.Reset();
继续之前的话题:
_suspendEvent.Set();
您可以使用类似的机制来发出退出线程的信号并等待两个事件,检测哪个事件被触发。
为了好玩,我将提供一个完整的示例:
You can use a similar mechanism to signal the thread to exit and wait on both events, detecting which event was signaled.
Just for fun I'll provide a complete example:
public class Worker
{
ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
ManualResetEvent _pauseEvent = new ManualResetEvent(true);
Thread _thread;
public Worker() { }
public void Start()
{
_thread = new Thread(DoWork);
_thread.Start();
}
public void Pause()
{
_pauseEvent.Reset();
}
public void Resume()
{
_pauseEvent.Set();
}
public void Stop()
{
_shutdownEvent.Set();
_pauseEvent.Set();
_thread.Join();
}
public void DoWork()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_shutdownEvent.WaitOne(0))
break;
}
}
}