mickG
mickG

Reputation: 335

Call a method only after jobs on other threads have terminated?

in my app I have two methods that load data from csv. These methods are loadData() and loadOtherData(). I want to run them in parallel so I have two threads to run them.

The loadData() method also populate one datagridview, while the data loaded by the loadOtherData() method are stored in a dictionary myDictionary.

After data loading is completed (so the methods running in the two threads have finished) I want to call another method updateGrids() that takes myDictionary as argument.

For updateGrids() to run properly, both loadData() and loadOtherData() must have run successfully cause otherwise the method doesn't have the data to work on.

How can I call method updateGrids() only when the other methods have terminated in other threads?

The structure is as follow:

    private void loadData_Click_1(object sender, EventArgs e)
    {
        ThreadStart thread1Start = new ThreadStart(loadData); // load data and fill the first datagridview
        ThreadStart thread2Start = new ThreadStart(loadOtherData); // load data and fill myDictionary
        Thread t1 = new Thread(thread1Start);
        Thread t2 = new Thread(thread2Start);
        t1.Start(); 
        t2.Start();

        updateGrids(myDictionary); // call this method to update remaining datagridviews
    }


    private void updateGrids(Dictionary<string, double> myDictionary)
    {
        // update the remaining datagridviews by using 
        // information in the first datagridview and in myDictionary
    }

But if I run this, I get the error when updateGrids() since it doesn't have the data to work with. How can I easily change the code to make it work?

Upvotes: 0

Views: 120

Answers (3)

Andy
Andy

Reputation: 8562

After you start your threads, you want to wait until they are done. So add these lines of code:

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

Join will cause the current thread to sleep until the thread being joined is complete.

Based on comments, I'm assuming this is WinForms. In this case Join will block the UI thread. You could create a third thread that will join the other two threads and then call Invoke to call your update method.

Since you're using .Net 4.5., you could use Async / Await; add the async modifier to your click method event handler and uses Tasks instead of Threads directly and await them. Other answers cover that, and you can see this blog for other details too.

Upvotes: -1

EZI
EZI

Reputation: 15354

You can use async/await to wait both tasks without blocking the UI

async private void loadData_Click_1(object sender, EventArgs e)
{
    await Task.WhenAll(Task.Run(() => loadData()), 
                       Task.Run(() => loadOtherData()));

    updateGrids(myDictionary); 
}

Upvotes: 1

Mike
Mike

Reputation: 91

You could stop using ThreadStart objects directly and use Tasks instead - have them returned from your loadData and loadOtherData methods.

You have either two options here:

Either Use Task.WaitAll if you're using .NET 4.0

or (more preferable)....

Make loadData and loadOtherData async in .NET 4.5 and above (or use the async BCL package in .NET 4.0). The when you call the methods, you can cache the Task objects they return and await a call to Task.WhenAll

public async Task LoadData(){ 

}

public async Task LoadOtherData() {

}

private async void loadData_Click_1(object sender, EventArgs e)
{
    var loadDataTask = LoadData();
    var loadOtherDataTask = LoadOtherData();
    await Task.WhenAll(loadDataTask, loadOtherDataTask);

    updateGrids(myDictionary);
} 

Upvotes: 2

Related Questions