kosnkov
kosnkov

Reputation: 5911

C# Threads, WaitHandle.WaitAll

Is that possible not not block winForm using WaitHandle.WaitAll(waitHandles) but just set another thread which will fire when get complate signal from WaitHandle.WaitAll?

Upvotes: 2

Views: 4203

Answers (4)

Brian Gideon
Brian Gideon

Reputation: 48949

I would not use WaitHandle.WaitAll. There are a couple of problems with this approach.

  • There is a 64 handle limit.
  • It cannot be used on an STA thread.
  • It promotes patterns that depend on the creation of multiple WaitHandle instances which obviously consume resource.

Instead, I typically use the CountdownEvent class when I want to wait on multiple events. Now, the problem you will have with that is that it still requires you to call Wait on some thread which is exactly what you are trying to avoid. The standard mechanism to avoid making a blocking call is to use the ThreadPool.RegisterWaitForSingleObject method. But, unfortunately that takes a WaitHandle and CountdownEvent does not inherit from that class.

The solution is to create your own CountdownWaitHandle class that can be used in the ThreadPool.RegisterWaitForSingleObject method. This approach will allow you to specify a callback delegate that will be executed once the WaitHandle is signaled.

Here is the most basic implemenation for the CountdownWaitHandle class. You will have to add all of the necessary harding code yourself, but this will get you started.

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();
    }
}

The idea here is that instead of using many different WaitHandle instances you use a single CountdownWaitHandle instance. Initialize the instance with the desired count and then call Signal to decrement the count. Once the count gets to zero the WaitHandle will go into the signaled state. So instead of calling Set on multiple WaitHandle instances and blocking with WaitHandle.WaitAll you now call Signal on this one instance and block by calling WaitOne. And again, you can push off the blocking call to the thread pool by using TheadPool.RegisterWaitForSingleObject which will invoke a callback when the WaitHandle is signaled.

Upvotes: 3

dsolimano
dsolimano

Reputation: 8986

Perhaps you could start another thread yourself, and call WaitHandle.WaitAll yourself on that thread? If you are not starting too many other threads, this should work fine.

Upvotes: 0

Moo-Juice
Moo-Juice

Reputation: 38825

Have a look at ManualResetEvent. Using this you can set the event when your thread has finished, and any other thread can either wait on this event, or check to see if it is in the signalled state.

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

Upvotes: 0

SLaks
SLaks

Reputation: 887225

You can call WaitAll in a background thread, then call BeginInvoke to move back to the UI thread.

Upvotes: 0

Related Questions