C# 仅在其他线程上的作业终止后调用方法?

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()正常运行,

在我的应用程序中,我有两种方法从csv加载数据。这些方法是
loadData()
loadOtherData()
。我想并行运行它们,所以我有两个线程来运行它们

loadData()
方法也会填充一个datagridview,而
loadOtherData()
方法加载的数据存储在dictionary
myDictionary

数据加载完成后(因此两个线程中运行的方法已经完成),我想调用另一个方法
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比本机使用线程对象更为传统,也会使他更容易处理异常非诉讼案件。