nop
nop

Reputation: 6311

ManualResetEvent and CancellationToken to stop thread until others are done

I have a function which is going to be processed by like 5 threads at same time but with different arguments passed. I want to wait to make the main thread wait for the rest threads and then release it. I'm not even sure if CancellationToken would work with Threadpool because all examples are with Tasks and I want to set up a button to stop threads at some point.

I'm aware of the fact there is a lot of information about threading but that's the actual problem. I don't know which threading classes are better or how to implement them because there are ambiguous examples. One source says that it should be done in one way and another in other way. Here are some examples that I saw. You can see that MSDN's example is ambiguous compared to the other 2 links or at least I'm missing the point. https://jeremylindsayni.wordpress.com/2016/03/26/how-to-use-manualresetevent-in-c-to-block-one-thread-until-another-has-completed/, How to make main thread to wait until other threads ends and https://learn.microsoft.com/en-us/dotnet/api/system.threading.manualresetevent?view=netframework-4.7.2.

private void DoJob(object state)
{
    Console.WriteLine("Delaying...");
    Thread.Sleep(3000);
    Console.WriteLine("Thread done");
    _manualResetEvent.Set();
}

// on some button click event
_manualResetEvent = new ManualResetEvent(false);

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}

_manualResetEvent.WaitOne();

Console.WriteLine("Main thread released");

In the example above, I wanted to make main thread wait for rest threads until they are done but the main thread is getting released after the first thread is done.

Delaying...
Delaying...
Delaying...
Delaying...
Thread done
Main thread released
Thread done
Thread done
Thread done

If I put WaitOne in each thread (DoJob method) and Set on the place of current WaitOne, the main thread is being released first and what I want is to release it after all other threads are done.

Upvotes: 0

Views: 1327

Answers (1)

Kevin Gosse
Kevin Gosse

Reputation: 39007

In your case, you really just use tasks:

var tasks = new List<Task>();

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    tasks.Add(Task.Run(() => DoJob(i)));
}

Task.WaitAll(tasks);

If for some reason you don't want to use tasks, you can have a look at CountdownEvent, which is precisely designed to wait on a definite number of asynchronous operations:

private void DoJob(object state)
{
    Console.WriteLine("Delaying...");
    Thread.Sleep(3000);
    Console.WriteLine("Thread done");
    _countdownEvent.Signal();
}

// on some button click event
_countdownEvent = new CountdownEvent(threadsNumericUpDown.Value);

for (int i = 0; i < threadsNumericUpDown.Value; i++)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(DoJob), i);
}

_countdownEvent.Wait();

Console.WriteLine("Main thread released");

Upvotes: 1

Related Questions