Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 主线程等待多个backgroundworker线程完成_C#_Multithreading - Fatal编程技术网

C# 主线程等待多个backgroundworker线程完成

C# 主线程等待多个backgroundworker线程完成,c#,multithreading,C#,Multithreading,我生成了多个backgroundworkerthreads,并希望我的主线程等待所有线程完成。解决方案是每次生成backgroundworker线程时向列表中添加一项,并在RunWorkerCompleted中删除它们。但是,如何将列表作为参数传递到RunWorkerCompleted FuncA() { foreach() { /* add an item to the list */ _bw.RunWorkerAsync(); } m_event.WaitOne();

我生成了多个backgroundworkerthreads,并希望我的主线程等待所有线程完成。解决方案是每次生成backgroundworker线程时向列表中添加一项,并在RunWorkerCompleted中删除它们。但是,如何将列表作为参数传递到RunWorkerCompleted

FuncA()
{
 foreach()
 {
    /* add an item to the list */
   _bw.RunWorkerAsync();
 }
 m_event.WaitOne(); /* Main thread waits here */
}
static bw_DoWork()
{

}
static bw_RunWorkerCompleted()
{ 
    /* delete item from list */
    /* if list is empty signal m_event.Set() */
}

将TPL与
await
一起使用,这非常简单:

对于.NET 4.0解决方案,您可以使用任务而不使用
wait

private void someEventHandler()
{
    Task.Factory.ContinueWhenAll(new[]{
        Task.Run(() => ComputeSomeValue()),
        Task.Run(() => ComputeSomeOtherValue()),
        Task.Run(() => ComputeYetAnotherValue())}
        , resultTask => DoSomethingWithResults(resultTask.Result);
}

如果您使用的是.NET Framework 4或更高版本,则可以使用System.Threading.CountdownEvent进行此操作。 在FuncA()内部,在启动后台工作程序之前,必须使用大量对象初始化CountdownEvent,在WorkerCompleted处理程序中,应该调用CountdownEvent的Signal()方法。
在所有工作线程完成之前不应继续的线程中,您必须调用CountdownEvent的Wait()方法,并在该方法之后调用所有必须稍后执行的代码。

在调用_bw.RunWorkerAsync()时,您可以将列表作为参数传递。RunWorkerAsync方法有一个重载方法,该方法将对象类型作为参数

您可以在bw_DoWork事件结束时从列表中删除项,而不是在bw_RunWorkerCompleted事件中删除项。后者应该在更新某些UI元素时使用

List<object> list = new List<object>();
FuncA()
{
    foreach()
    {
        /* add an item to the list */
       _bw.RunWorkerAsync(list);
     }
    m_event.WaitOne(); /* Main thread waits here */
}
static bw_DoWork()
{
    // Do the stuff.

    /* delete item from list */
    var list = e.Argument as List<object>;
    /* if list is empty signal m_event.Set() */
}
List List=新列表();
FuncA()
{
foreach()
{
/*将项目添加到列表中*/
_RunWorkerAsync(列表);
}
m_event.WaitOne();/*主线程在此等待*/
}
静态工作
{
//做这件事。
/*从列表中删除项目*/
var list=e.参数作为列表;
/*如果列表为空,则信号m_event.Set()*/
}

您不想阻止主线程。这将冻结您的UI。另外,顺便说一句,它将阻止触发
RunWorkerCompleted
。您能否解释一下,如果主线程被阻止,RunWorkerCompleted将如何准确地不被触发?BGW将把完成的事件封送到主线程,主线程随后无法处理请求,因为它被阻止,直到当前请求完成。在BGW completed事件运行之前,它不会完成。谢谢你。死锁问题只存在于后台工作线程吗?死锁问题是因为您正在阻塞UI线程。不要那样做。您不希望阻止UI线程。如果您想在所有后台任务完成时(在UI线程中)简单地做一些事情,您可以这样做。我的回答向您展示了一种方法(我认为这是最简单的方法)。不幸的是,我的应用程序运行在.NET framework 4.0中,无法支持TPL:(.由于其他依赖性约束,我也无法更改框架。还有其他解决方法吗?当然,还有其他方法,尽管它们没有那么好。我添加了一种可能性。这将导致死锁。在等待后台工作人员时,您将阻塞UI线程,
RunWorkerCompleted
事件将不会成为一个问题无法在处理程序封送到UI线程时运行。由于每个处理程序都在等待另一个处理程序,因此会出现死锁。@Servy这取决于您等待CountdownEvent的位置。我很清楚,您应该从一个单独的线程更新UI,从而在该线程中等待完成。我没有编写需要粘贴的确切代码n一个项目,但只是一个应该如何实现的想法!您的回答特别提到了在
FuncA
中等待,这显然是在UI线程中运行的。创建一个全新的线程只是等待所有这些工作人员完成,这也是完全不合适的。您根本不需要一个线程来完成任务真的吗?“在线程中,在所有工作人员完成之前,该线程不应继续”-我要说的是,应该在FuncA()中调用Wait?谁说线程只能等待?这是你说的,不是我说的。OP说他正在寻找一种在主线程中等待的方法。你说他应该使用
倒计时事件
在线程中等待,该线程不应该继续,这就是UI线程。是的,你应该这样做是我说的不要创建一个新线程,让它什么也不做,只能等待其他事情完成。这是糟糕的设计,浪费系统资源,而且还有更好的选择。这会在长时间运行的工作期间阻塞UI线程,从而冻结整个UI。这是不应该做的,UI线程应该这样做当此工作正在进行时,您可以继续处理消息。
List<object> list = new List<object>();
FuncA()
{
    foreach()
    {
        /* add an item to the list */
       _bw.RunWorkerAsync(list);
     }
    m_event.WaitOne(); /* Main thread waits here */
}
static bw_DoWork()
{
    // Do the stuff.

    /* delete item from list */
    var list = e.Argument as List<object>;
    /* if list is empty signal m_event.Set() */
}