be notified when all background threadpool threads are finished

梦想与她 提交于 2019-11-27 16:32:26

问题


I have a scenario when I start 3..10 threads with ThreadPool. Each thread does its job and returns to the ThreadPool. What are possible options to be notified in main thread when all background threads have finished?

Currently I'm using a homegrown method with incrementing a variable for each of created threads and decrementing it when a background thread is about to finish. This works just fine, but I was curious if there are better options.


回答1:


Decrementing a variable (between threads) is a little bit risky unless done with Interlocked.Decrement, but that approach should be fine if you have the last thread (i.e. when it gets to zero) raise an event. Note that it would have to be in a "finally" block to avoid losing it in the case of exceptions (plus you don't want to kill the process).

In "Parallel Extensions" (or with .NET 4.0), you might also look at the Parallel.ForEach options here... that might be another way of getting everything done as a block. Without having to watch them all manually.




回答2:


Try this: https://bitbucket.org/nevdelap/poolguard

using (var poolGuard = new PoolGuard())
{
    for (int i = 0; i < ...
    {
        ThreadPool.QueueUserWorkItem(ChildThread, poolGuard);
    }
    // Do stuff.
    poolGuard.WaitOne();
    // Do stuff that required the child threads to have ended.

void ChildThread(object state)
{
    var poolGuard = state as PoolGuard;
    if (poolGuard.TryEnter())
    {
        try
        {
            // Do stuff.
        }
        finally
        {
            poolGuard.Exit();
        }
    }
}

Multiple PoolGuards can be used in different ways to track when threads have ended, and handles threads that haven't started when the pool is already closed.




回答3:


If its not more than 64 Threads to wait on, you can use the WaitHandle.WaitAll method like this:

List<WaitHandle> events = new List<WaitHandle>();
for (int i = 0; i < 64; i++)
{
    ManualResetEvent mre = new ManualResetEvent(false);
    ThreadPool.QueueUserWorkItem(
        delegate(object o)
        {
            Thread.Sleep(TimeSpan.FromMinutes(1));
            ((ManualResetEvent)o).Set();
        },mre);
    events.Add(mre);
}
WaitHandle.WaitAll(events.ToArray());

The execution will wait till all ManualResetEvents are set, alternatively, you may use WaitAny method.

The WaitAny and WaitAll methods will block the execution, but you can simply use the list, or a dictionary of ManualResetEvents linked to the task that is spawn for later determining if the thread is done though.




回答4:


There's isn't a built-in way to do this at the moment - I find it one of the biggest pains about using pool threads.

As Marc says, this is the kind of stuff which is being fixed in Parallel Extensions / .NET 4.0.




回答5:


Couldn't you give each thread a distinct ManualResetEvent and have each set the event when done. Then, in the main thread you can wait on all the events passed in.




回答6:


Marc's solution is best if you just want to know when all the jobs are finished, and don't need finer info than that (as seems to be your case).

If you wanted some thread to spawn jobs, and some other thread to to receive the notifications, you could use WaitHandle. The code is much longer.

    int length = 10;
    ManualResetEvent[] waits = new ManualResetEvent[length];
    for ( int i = 0; i < length; i++ ) {
        waits[i] = new ManualResetEvent( false );
        ThreadPool.QueueUserWorkItem( (obj) => {
            try {

            } finally {
                waits[i].Set();
            }
        } );
    }

    for ( int i = 0; i < length; i++ ) {
        if ( !waits[i].WaitOne() )
            break;
    }

The WaitOne method, as written, always returns true, but I have written it like that to make you remember that some overloads take a Timeout as an argument.




回答7:


What about using Semaphore, and set a limit to it as much as your thread pool. Have a method to fetch a Semaphore, to be called when you start your thread, release it when your thread end and raise an event if you've taken up all the Semaphore.



来源:https://stackoverflow.com/questions/358721/be-notified-when-all-background-threadpool-threads-are-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!