0

I am working on a .NET Windows Forms application using Visual Studio 2010.

In this application, I need four background threads for underlying data transmission. When ALL the four threads finished, another round of four underlying data transmissions will be started using the four threads again.

The form UI needs to be responsive all the time. My problem is: How can I control the running of the four threads? Like: How do I know that all threads are finished? Using a volatile global counter?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
skyfree
  • 867
  • 2
  • 10
  • 29

2 Answers2

2

.NET 4 kindly provides class Task and related to unify high level of asynchronous API. So you can safely switch from your BackgroundWorker based design to Task based, and then you will see how easy it is to wait till all Tasks finish with Task.Factory.ContinueWhenAll.

See Async Tasks - Simplify Asynchronous Programming with Tasks.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lex Li
  • 60,503
  • 9
  • 116
  • 147
1

To answer your question about using specifically four threads, below is a quick sketch using BackgroundWorker. The idea here is to set up four tasks, track the number of running tasks and, when they're all done restart. For a discussion of volatile vs interlocked, see Stack Overflow question Volatile vs. Interlocked vs. lock.

This will give you what you're asking for (four threads, responsive UI), but there's no error handling, and there could be other problems. Is it possible that one BackgroundWorker would hang (maybe your 'data transmission' goes haywire) in which case you'll end up in a bad state?

public partial class Form1 : Form  {
    private int workersRunning = 0;
    private List<BackgroundWorker> workers = new List<BackgroundWorker>();

    public Form1()  {
        InitializeComponent();
        for (int i = 0; i < 4; i++)  {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(this.worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.worker_RunWorkerCompleted);
            workers.Add(worker);
        }
    }

    private void button1_Click(object sender, EventArgs e) {
        this.StartWork();
    }

    private void StartWork() {
        workers.ForEach(worker => worker.RunWorkerAsync());
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
        Interlocked.Decrement(ref workersRunning);
        Console.WriteLine("Worker reported completion from thread id " + e.Result);
        if(this.workersRunning == 0) {
            Console.WriteLine("All workers are done. Start again");
            this.StartWork();
        }  else  {
            Console.WriteLine(this.workersRunning + " workers are still running.");
        }
    }

    void worker_DoWork(object sender, DoWorkEventArgs e) {
        Interlocked.Increment(ref workersRunning);
        int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Doing work on thread #" + threadId);

        Thread.Sleep(new Random().Next(2000, 5000));

        e.Result = "Work done on thread id " + threadId;
    }
}
Community
  • 1
  • 1
Jeffrey Knight
  • 5,888
  • 7
  • 39
  • 49