【发布时间】:2010-11-25 04:28:55
【问题描述】:
这可能不会使用 WaitHandle.WaitAll(waitHandles) 阻止 winForm,而是设置另一个线程,当从 WaitHandle.WaitAll 获得 complate 信号时将触发该线程?
【问题讨论】:
-
你应该接受你的问题的答案。
标签: c# multithreading
这可能不会使用 WaitHandle.WaitAll(waitHandles) 阻止 winForm,而是设置另一个线程,当从 WaitHandle.WaitAll 获得 complate 信号时将触发该线程?
【问题讨论】:
标签: c# multithreading
我不会使用WaitHandle.WaitAll。这种方法有几个问题。
WaitHandle 实例的模式,这些实例显然会消耗资源。相反,当我想等待多个事件时,我通常使用CountdownEvent 类。现在,您将遇到的问题是它仍然需要您在某个线程上调用Wait,这正是您要避免的。避免进行阻塞调用的标准机制是使用ThreadPool.RegisterWaitForSingleObject 方法。但是,不幸的是,这需要 WaitHandle 和 CountdownEvent 不会从该类继承。
解决方案是创建您自己的CountdownWaitHandle 类,该类可以在ThreadPool.RegisterWaitForSingleObject 方法中使用。这种方法将允许您指定一个回调委托,该委托将在WaitHandle 发出信号后执行。
这是CountdownWaitHandle 类的最基本实现。您必须自己添加所有必要的硬编码,但这会让您开始。
public class CountdownWaitHandle : WaitHandle
{
private int m_Count = 0;
private ManualResetEvent m_Event = new ManualResetEvent(false);
public CountdownWaitHandle(int initialCount)
{
m_Count = initialCount;
}
public void AddCount()
{
Interlocked.Increment(ref m_Count);
}
public void Signal()
{
if (Interlocked.Decrement(ref m_Count) == 0)
{
m_Event.Set();
}
}
public override bool WaitOne()
{
return m_Event.WaitOne();
}
}
这里的想法是不要使用许多不同的WaitHandle 实例,而是使用单个CountdownWaitHandle 实例。使用所需计数初始化实例,然后调用Signal 以减少计数。一旦计数变为零,WaitHandle 将进入信号状态。因此,与其在多个WaitHandle 实例上调用Set 并用WaitHandle.WaitAll 阻塞,不如在这个实例上调用Signal 并通过调用WaitOne 阻塞。同样,您可以使用TheadPool.RegisterWaitForSingleObject 将阻塞调用推到线程池,这将在WaitHandle 发出信号时调用回调。
【讨论】:
您可以在后台线程中调用 WaitAll,然后调用 BeginInvoke 以返回 UI 线程。
【讨论】:
看看ManualResetEvent。使用它你可以在你的线程完成时设置事件,并且任何其他线程可以等待这个事件,或者检查它是否处于信号状态。
ManualResetEvent ev = new ManualReserEvent();
while(Users["user428547"].AcceptanceRate == 0)
{
// this might take a long time
};
ev.Set(); // done, he accepted an answer.
【讨论】:
也许您可以自己启动另一个线程,并在该线程上自己调用WaitHandle.WaitAll?如果您没有启动太多其他线程,这应该可以正常工作。
【讨论】: