如何取消阻止对 AutoResetEvent 对象调用 WaitOne 方法的线程?
下面是一个具有“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 方法 的 MSDN 文档。我引用以下文档的相关部分:
如果 millisecondsTimeout 为零,则该方法不会阻塞。它测试等待句柄的状态并立即返回。
在 do..while 循环中,我调用 Set方法。这会释放可能因调用 WaitOne 方法(在“SomeMethod”方法内编码)而阻塞的单个线程。接下来,我测试“theEvent”对象的状态,只是为了知道它是否已发出信号。此测试是通过调用带有超时参数的 WaitOne 方法的重载版本来完成的。我在调用 WaitOne 方法时使用的参数为零,根据文档,这会导致调用立即返回布尔值。如果返回值为 true,则“theEvent”对象处于有信号状态。如果在“SomeMethod”方法中调用“WaitOne”方法时至少有一个线程被阻塞,则对“Set”方法(在“UnblockAll”方法内编码)的调用将解除该线程的阻塞。因此,在“UnblockAll”方法中的 do..while 语句末尾调用“WaitOne”方法将返回 false。仅当没有线程被阻塞时,返回值才为 true。
上述推理是否正确?如果正确,该技术是否是处理我的问题的标准方法?我尝试主要在 .net Compact-framework 2.0 平台上使用该解决方案。
Below is a class having the method 'SomeMethod' that illustrates my problem.
class SomeClass
{
AutoResetEvent theEvent = new AutoResetEvent(false);
// more member declarations
public void SomeMethod()
{
// some code
theEvent.WaitOne();
// more code
}
}
The method is designed to be thread-safe and will be called in different threads. Now my question is how is it possible to unblock all threads that have called the 'WaitOne' method on the 'theEvent' object at any point of time? This requirement frequently arises in my design because I need to be able to gracefully stop and start my multi-threaded program. It seems to me that it's fairly simple to start a multi-threaded program, but tricky to stop one.
Here's what I have tried so far which apparently works. But is this the standard approach?
public void UnblockAll()
{
do
{
theEvent.Set();
} while (theEvent.WaitOne(0));
}
The 'UnblockAll' method is a member of the 'SomeClass' class. The technique used here is based on the MSDN documentation of the WaitOne method. I am quoting the relevant part of the documentation below:
If millisecondsTimeout is zero, the method does not block. It tests the state of the wait handle and returns immediately.
In the do..while loop, I call the Set method. This releases a single thread that may have blocked due to a call to the WaitOne method (coded inside the 'SomeMethod' method). Next I test the state of the 'theEvent' object just to know whether it's signalled. This test is done by calling the overloaded version of the WaitOne method that takes a time out parameter. The argument which I use when I call the WaitOne method is zero, which as per the documentation results in the call returning immediately with a boolean value. If the return value is true, then the 'theEvent' object was in a signalled state. If there was at least a single thread blocked on the call to the 'WaitOne' method in the 'SomeMethod' method, the call to the 'Set' method (coded inside the 'UnblockAll' method) would unblock it. Consequently the call to the 'WaitOne' method at the end of the do..while statement in the 'UnblockAll' method would return false. The return value is true only if there were no threads blocked.
Is the above reasoning right and if it's right, is the technique a standard way to deal with my problem? I am trying to use the solution primarily on the .net compact-framework 2.0 platform.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您有三个可行的选择。每一种都有其自身的优点和缺点。选择最适合您的具体情况的一种。
选项 1 - 轮询
WaitHandle
。不要进行无限期的阻塞调用,而是使用超时的调用,并在未给出关闭请求的情况下恢复阻塞。
选项 2 - 使用单独的
WaitHandle
来请求关闭选项 3 - 使用
Thread.Interrupt
不要将此与线程.中止。中止线程肯定是不安全的,但中断线程则完全不同。
Thread.Interrupt
将“戳”BCL 中使用的内置阻塞调用,包括Thread.Join
、WaitHandle.WaitOne
、Thread。睡眠
等You have three viable options. Each one has its own advantages and disadvantages. Pick the one that works best for your specific situation.
Option 1 - Poll the
WaitHandle
.Instead of doing an indefinite blocking call use one with a timeout and reinstate the block if a shutdown request has not been given.
Option 2 - Use a separate
WaitHandle
for requesting shutdownOption 3 - Use
Thread.Interrupt
Do not confuse this with
Thread.Abort
. Aborting a thread is definitely unsafe, but interrupting a thread is completely different.Thread.Interrupt
will "poke" the builtin blocking calls used in the BCL includingThread.Join
,WaitHandle.WaitOne
,Thread.Sleep
, etc.您的例程可能在大多数情况下都有效,但我认为不能保证等待线程之一会在关闭循环设置事件的时间和关闭循环再次检查事件的时间之间重置事件。
我发现 AutoResetEvent 和 ManualResetEvent 类非常适合非常简单的场景。每当需求出现任何奇怪的情况时,我都会快速切换到更灵活的等待并脉冲模式。
如果您不需要任何清理,您可以将工作线程设置为后台线程,然后当主线程退出时它们就会停止。
您还可以定义第二个名为 stopRequest 的 ManualResetEvent 并等待来自任一事件的信号。但是,紧凑框架可能不支持这一点。
Your routine will probably work most of the time, but I don't think there's any guarantee that one of the waiting threads will reset the event between the time that your shutdown loop sets it and the time that your shutdown loop checks it again.
I find that the AutoResetEvent and ManualResetEvent classes work great for really simple scenarios. Any time there's anything odd about the requirements, I quickly switch to the more flexible Wait And Pulse pattern.
If you don't require any clean up, you could make your worker threads background threads, and then they'll just stop when the main thread exits.
You might also be able to define a second ManualResetEvent called stopRequest and wait on a signal from either event. However, that might not be supported on the compact framework.
线程是否中止 适用于你的框架吗?
Does thread abort work for your framework?