C#Threads,WaitHandle.WaitAll

时间:2010-11-21 18:51:23

标签: c# multithreading

这可能不会阻止winForm使用WaitHandle.WaitAll(waitHandles)但只是设置另一个线程,当从WaitHandle.WaitAll获取complate信号时将触发吗?

4 个答案:

答案 0 :(得分:3)

我不会使用WaitHandle.WaitAll。这种方法存在一些问题。

  • 有64个句柄限制。
  • 不能在STA线程上使用。
  • 它促进了依赖于创建明显消耗资源的多个WaitHandle实例的模式。

相反,我想在等待多个事件时使用CountdownEvent类。现在,您将遇到的问题是它仍然需要您在某个线程上调用Wait,这正是您要避免的。避免进行阻塞调用的标准机制是使用ThreadPool.RegisterWaitForSingleObject方法。但是,遗憾的是,WaitHandleCountdownEvent不会从该类继承。

解决方案是创建自己的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将进入信号状态。因此,您不必在多个Set个实例上调用WaitHandle并使用WaitHandle.WaitAll进行阻止,而是在此一个实例上调用Signal,然后通过调用WaitOne来阻止。同样,您可以使用TheadPool.RegisterWaitForSingleObject推迟对线程池的阻塞调用,WaitHandle将在{{1}}发出信号时调用回调。

答案 1 :(得分:0)

您可以在后台线程中调用WaitAll,然后调用BeginInvoke以返回UI线程。

答案 2 :(得分:0)

看看ManualResetEvent。使用它可以在线程完成时设置事件,任何其他线程都可以等待此事件,或检查它是否处于信号状态。

ManualResetEvent ev = new ManualReserEvent();
while(Users["user428547"].AcceptanceRate == 0)
{
   // this might take a long time
};
ev.Set(); // done, he accepted an answer.

答案 3 :(得分:0)

也许您可以自己启动另一个帖子,并在该线程上自己调用WaitHandle.WaitAll?如果你没有开始太多其他线程,这应该可以正常工作。