Kaushik
Kaushik

Reputation: 449

Synchronizing threads in C#

I have a Forms based application. The UI is handled by a thread. From the UI Thread, I create 3 threads to perform some processing.

Thread t1 = new Thread(() => performprocessing());
Thread t2 = new Thread(() => performprocessing());
Thread t3 = new Thread(() => performprocessing());

Now, I want to execute a statement in the UI thread after all the 3 threads finish their execution.So, I did the following:

do 
{

} while (t1.IsAlive || t2.IsAlive || t3.IsAlive);
/*--execute statement---*/

But I want the UI to remain responsive as well. In this case the UI thread is stuck in the loop until all the three threads finish execution. How do I perform this?

I read about manual and auto reset events but I am not sure how to use them in this case. Kindly guide me.

Upvotes: 1

Views: 226

Answers (4)

Maksim Solodovnikov
Maksim Solodovnikov

Reputation: 824

Spawning new threads is a bad practice, use a thread pool instead.

{
    var t1 = Task.Run(() => doSomething1());
    var t2 = Task.Run(() => doSomething2());
    var t3 = Task.Run(() => doSomething3());

    Task.WhenAll(t1, t2, t3).ContinueWith(t => doSomething4());
}

A cleaner approach for .NET 4.5 is to use async/await.

async void Form1_Load(object sender, EventArgs e)
{ 
    var t1 = Task.Run(() => doSomething1());
    var t2 = Task.Run(() => doSomething2());
    var t3 = Task.Run(() => doSomething3());

    await Task.WhenAll(t1, t2, t3);
    doSomething4();
}

.NET 4.0 does not define Task.Run() and Task.WhenAll(), use Task.Factory instead.

{
    var t1 = Task.Factory.StartNew(() => doSomething1());
    var t2 = Task.Factory.StartNew(() => doSomething2());
    var t3 = Task.Factory.StartNew(() => doSomething3());

    Task.Factory.ContinueWhenAll(new[] { t1, t2, t3}, tasks => doSomething4());
}

Upvotes: 2

Ketan
Ketan

Reputation: 1

If for whatever reason you don't wish to use Task as mentioned by solmaks then you could use the Join() method which will block until the thread has completed.

Thread t1 = new Thread(() => performprocessing());
Thread t2 = new Thread(() => performprocessing());
Thread t3 = new Thread(() => performprocessing());

t1.Join();
t2.Join();
t3.Join();

I wouldn't recommend using this on the UI thread however as it could make your application unresponsive.

Upvotes: -1

Marko
Marko

Reputation: 2734

Use a background worker thread and you can keep the ui responsive and send progress.

void Form1_Load(object sender, EventArgs e)
        {
            BackgroundWorker b1 = new BackgroundWorker();
            BackgroundWorker b2 = new BackgroundWorker();
            BackgroundWorker b3 = new BackgroundWorker();
            b1.RunWorkerCompleted += b1_RunWorkerCompleted;
            b2.RunWorkerCompleted += b2_RunWorkerCompleted;
            b3.RunWorkerCompleted += b3_RunWorkerCompleted;
        }

        void b1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
        }

        void b2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
        }

        void b3_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
        }

Upvotes: 0

Dan
Dan

Reputation: 10538

Try using Barrier.

You need to pass the Barrier instance into your thread, and then use Barrier.SignalAndWait() from within the thread. Specify the number of signals you need to proceed in the constructor of Barrier.

Once all signals have been received, the threads that are Waiting will stop blocking.

Upvotes: 5

Related Questions