下面是一个具有'SomeMethod'方法的类来说明我的问题。
class SomeClass
{
AutoResetEvent theEvent = new AutoResetEvent(false);
// more member declarations
public void SomeMethod()
{
// some code
theEvent.WaitOne();
// more code
}
}
该方法设计为线程安全的,并将在不同的线程中调用。现在我的问题是如何在任何时间点取消阻止在'theEvent'对象上调用'WaitOne'方法的所有线程?这个要求经常出现在我的设计中,因为我需要能够优雅地停止和启动我的多线程程序。在我看来,启动一个多线程程序相当简单,但很难阻止它。
这是我到目前为止所尝试过的,显然有效。但这是标准方法吗?
public void UnblockAll()
{
do
{
theEvent.Set();
} while (theEvent.WaitOne(0));
}
'UnblockAll'方法是'SomeClass'类的成员。此处使用的技术基于WaitOne method的MSDN文档。我引用了以下文档的相关部分:
如果millisecondsTimeout为零,则该方法不会阻止。它测试等待句柄的状态并立即返回。
在do..while循环中,我调用Set method。这释放了一个可能由于调用WaitOne方法而被阻塞的线程(在'SomeMethod'方法中编码)。接下来,我测试'theEvent'对象的状态,只是为了知道它是否有信号。此测试是通过调用带有超时参数的WaitOne方法的重载版本来完成的。我在调用WaitOne方法时使用的参数为零,根据文档结果,调用立即返回一个布尔值。如果返回值为true,则'theEvent'对象 处于信号状态。如果在'SomeMethod'方法中对'WaitOne'方法的调用至少阻塞了一个线程,则调用'Set'方法(在'UnblockAll'方法中编码)将解除阻塞。因此,在'UnblockAll'方法中do..while语句结束时对'WaitOne'方法的调用将返回false。仅当没有线程被阻止时,返回值才为真。
上述推理是否正确,如果正确,该技术是解决我问题的标准方法吗?我试图主要在.net compact-framework 2.0平台上使用该解决方案。
答案 0 :(得分:11)
您有三种可行的选择。每个人都有自己的优点和缺点。选择最适合您特定情况的那个。
选项1 - 轮询WaitHandle
。
如果没有给出关闭请求,则不要进行无限期阻塞调用而是使用超时阻塞并恢复阻止。
public void SomeMethod()
{
while (!yourEvent.WaitOne(POLLING_INTERVAL))
{
if (IsShutdownRequested())
{
// Add code to end gracefully here.
}
}
// Your event was signaled so now we can proceed.
}
选项2 - 使用单独的WaitHandle
请求关闭
public void SomeMethod()
{
WaitHandle[] handles = new WaitHandle[] { yourEvent, shutdownEvent };
if (WaitHandle.WaitAny(handles) == 1)
{
// Add code to end gracefully here.
}
// Your event was signaled so now we can proceed.
}
选项3 - 使用Thread.Interrupt
不要将此与Thread.Abort
混淆。中止线程绝对不安全,但中断线程完全不同。 Thread.Interrupt
将“戳”BCL中使用的内置阻止调用,包括Thread.Join
,WaitHandle.WaitOne
,Thread.Sleep
等。
答案 1 :(得分:3)
您的例程可能在大多数情况下都可以正常工作,但我认为没有任何保证其中一个等待线程会在关闭循环设置它和关闭循环检查它之间重置事件试。
我发现AutoResetEvent和ManualResetEvent类对于非常简单的场景非常有用。任何时候对要求都有些奇怪,我会迅速切换到更灵活的Wait And Pulse pattern。
如果你不需要任何清理,你可以让你的工作线程后台线程,然后它们只会在主线程退出时停止。
您也可以定义第二个名为stopRequest的ManualResetEvent,并等待来自任一事件的信号。但是,紧凑框架可能不支持。
答案 2 :(得分:1)
thread abort是否适用于您的框架?