English 中文(简体)
Multi-Threading - waiting for all threads to be signalled
原标题:

I have scenarios where I need a main thread to wait until every one of a set of possible more than 64 threads have completed their work, and for that I wrote the following helper utility, (to avoid the 64 waithandle limit on WaitHandle.WaitAll())

    public static void WaitAll(WaitHandle[] handles)
    {
        if (handles == null)
            throw new ArgumentNullException("handles",
                "WaitHandle[] handles was null");
        foreach (WaitHandle wh in handles) wh.WaitOne();
    }

With this utility method, however, each waithandle is only examined after every preceding one in the array has been signalled... so it is in effect synchronous, and will not work if the waithandles are autoResetEvent wait handles (which clear as soon as a waiting thread has been released)

To fix this issue I am considering changing this code to the following, but would like others to check and see if it looks like it will work, or if anyone sees any issues with it, or can suggest a better way ...

Thanks in advance:

    public static void WaitAllParallel(WaitHandle[] handles)
    {
        if (handles == null)
            throw new ArgumentNullException("handles",
                "WaitHandle[] handles was null");
        int actThreadCount = handles.Length;
        object locker = new object();
        foreach (WaitHandle wh in handles)
        {
            WaitHandle qwH = wh;
            ThreadPool.QueueUserWorkItem(
                 delegate
                 {
                     try { qwH.WaitOne(); }
                     finally { lock(locker) --actThreadCount; }
                 });
        }
        while (actThreadCount > 0) Thread.Sleep(80);
    }
问题回答

If you know how many threads you have, you can use an interlocked decrement. This is how I usually do it:

 {
 eventDone = new AutoResetEvent();
 totalCount = 128;
 for(0...128) {ThreadPool.QueueUserWorkItem(ThreadWorker, ...);}
 }

 void ThreadWorker(object state)
 try
 {
   ... work and more work
 }
 finally
 {
   int runningCount = Interlocked.Decrement(ref totalCount);
   if (0 == runningCount)
   {
     // This is the last thread, notify the waiters
     eventDone.Set();
   }
 }

Actually, most times I don t even signal but instead invoke a callback continues the processing from where the waiter would continue. Less blocked threads, more scalability.

I know is different and may not apply to your case (eg. for sure will not work if some of thoe handles are not threads, but I/O or events), but it may worth thinking about this.

I m not sure what exactly you re trying to do, but would a CountdownEvent (.NET 4.0) conceptually solve your problem?

I m not a C# or .NET programmer, but you could use a semaphore that is posted when one of your worker threads exits. The monitoring thread would simply wait on the semaphore n times where n is the number of worker threads. Semaphores are traditionally used to count resources in use but they can be used to count jobs completed by waiting on the same semaphore for n times.

When working with lots of simultaneous threads, I prefer to add each thread s ManagedThreadId into a Dictionary when I start the thread, and then have each thread invoke a callback routine that removes the dying thread s id from the Dictionary. The Dictionary s Count property tells you how many threads are active. Use the value side of the key/value pair to hold info that your UI thread can use to report status. Wrap the Dictionary with a lock to keep things safe.

ThreadPool.QueueUserWorkItem(o =>
{
    try
    {
        using (var h = (o as WaitHandle))
        { 
            if (!h.WaitOne(100000))
            {
                // Alert main thread of the timeout
            }
        }
    }
    finally
    {
        Interlocked.Decrement(ref actThreadCount);
    }
 }, wh);




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签