C# 仅在其他线程上的作业终止后调用方法?
在我的应用程序中,我有两种方法从csv加载数据。这些方法是C# 仅在其他线程上的作业终止后调用方法?,c#,multithreading,winforms,asynchronous,.net-4.5,C#,Multithreading,Winforms,Asynchronous,.net 4.5,在我的应用程序中,我有两种方法从csv加载数据。这些方法是loadData()和loadOtherData()。我想并行运行它们,所以我有两个线程来运行它们 loadData()方法也会填充一个datagridview,而loadOtherData()方法加载的数据存储在dictionarymyDictionary中 数据加载完成后(因此两个线程中运行的方法已经完成),我想调用另一个方法updateGrids(),该方法将myDictionary作为参数 要使updateGrids()正常运行,
loadData()
和loadOtherData()
。我想并行运行它们,所以我有两个线程来运行它们
loadData()
方法也会填充一个datagridview,而loadOtherData()
方法加载的数据存储在dictionarymyDictionary
中
数据加载完成后(因此两个线程中运行的方法已经完成),我想调用另一个方法updateGrids()
,该方法将myDictionary
作为参数
要使updateGrids()
正常运行,必须成功运行loadData()
和loadOtherData()
,否则该方法将无法处理数据
只有当其他方法在其他线程中终止时,我如何调用方法updateGrids()
结构如下:
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
}
private void loadData\u Click\u 1(对象发送方,事件参数e)
{
ThreadStart thread1Start=newthreadstart(loadData);//加载数据并填充第一个datagridview
ThreadStart thread2Start=newthreadstart(loadOtherData);//加载数据并填充myDictionary
螺纹t1=新螺纹(螺纹1开始);
螺纹t2=新螺纹(螺纹2开始);
t1.Start();
t2.Start();
updateGrids(myDictionary);//调用此方法来更新剩余的DataGridView
}
私有void updateGrids(字典myDictionary)
{
//使用更新其余的DataGridView
//第一个datagridview和myDictionary中的信息
}
但是如果我运行它,我会在
updateGrids()
时出错,因为它没有数据可处理。如何轻松地更改代码以使其正常工作?您可以停止直接使用ThreadStart对象,而改用任务-让它们从loadData和loadOtherData方法返回
您在此处有两种选择:
如果使用的是.NET 4.0,请使用Task.WaitAll
或者(更可取)
在.NET 4.5及更高版本中使loadData和loadOtherData异步(或在.NET 4.0中使用异步BCL包)。调用这些方法时,可以缓存它们返回的任务对象,并等待对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);
}
在启动线程之后,您希望等待它们完成。因此,添加以下代码行:
t1.Join();
t2.Join();
将导致当前线程休眠,直到正在连接的线程完成
根据评论,我假设这是WinForms。在这种情况下,Join
将阻止UI线程。您可以创建第三个线程来连接其他两个线程,然后调用update方法
因为您使用的是.NET4.5,所以可以使用Async/Await;将async
修饰符添加到click方法事件处理程序中,并直接使用任务而不是线程,然后等待它们。其他答案也涵盖了这一点,您也可以查看其他详细信息。您可以在不阻塞UI的情况下等待这两个任务
async private void loadData_Click_1(object sender, EventArgs e)
{
await Task.WhenAll(Task.Run(() => loadData()),
Task.Run(() => loadOtherData()));
updateGrids(myDictionary);
}
所有工作线程都应提供检查它们是否完成工作的可能性(简单计数器即可)。在作业结束时,他们应该调用一个检查所有线程作业是否完成的方法,并调用updateGrid()
。您使用的是什么版本的.Net?这会影响答案。谢谢,现在添加到标题中。我正在使用4.5I从标题中删除它;标签是这样的细节的首选位置。这似乎不像预期的那样有效。我试过了,但应用程序没有响应,我需要停止程序。@Sinatr“创建第三个线程连接其他两个线程,然后调用Invoke”不是一个完整的解决方案吗?如果他那样做了,它会像预期的那样工作。或者你认为我应该为他写代码吗?我需要声明loadData()和loadOtherData(异步)才能并行运行吗?@mickG不,我假设它们是void xxx()
谢谢,这是预期的效果。这是实现这一点的最佳方法吗?@mickG“最佳方法”可能非常主观。但我也这么认为。我明白了,你能确认这不会在较旧的.NET版本上运行吗?我看不到反对票,但由于OP没有使用async/Wait,你没有完全回答这个问题。建议一个替代方案是可以的,但OP可能更适合线程,你也应该回答如何使用它。不是吗他的否决票已经被删除。OP使用的是.NET 4.5。我不认为他使用的是.NET 4.5有什么关系。他的问题是如何让这个与线程一起工作,所以你应该回答这个问题。如果你愿意,建议async/Wait,但使用线程没有任何问题(由于它存在的时间更长,所以有很多关于它的信息)。我不确定我是否真的理解你的观点。任务隐式地使用CLR中的线程。虽然他最初的问题包含使用线程对象的片段,但他没有说他受此限制。在.NET 4.5中使用async/await和Tasks比本机使用线程对象更为传统,也会使他更容易处理异常非诉讼案件。