如何等待多个线程执行完成以后,再做处理的问题?

rehuo 2017-10-30 01:10:50
我现在有多个比较耗费时间的任务需要并行执行,每个任务都需要通知UI线程,更新前台显示,等这些任务都执行完毕以后,然后UI线程再进行下一步操作,比如通知用户等等。如果使用ManualResetEvent进行控制,执行顺序就有些问题。测试代码如下:
public partial class Form1 : Form
{
private SendTest sendtest ;
public delegate void DataUpdate(byte[] data, string type, ManualResetEvent sign);
public DataUpdate OnDataUpdate;
private static List<ManualResetEvent> mre = new List<ManualResetEvent>();
public Form1()
{
InitializeComponent();

sendtest = new SendTest(this);
OnDataUpdate += UpdateData;
}
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.AppendText("开始处理!" + Environment.NewLine);
ManualResetEvent sign = new ManualResetEvent(false);
mre.Add(sign);
sendtest.Send(null, "1", sign);
sign = new ManualResetEvent(false);
mre.Add(sign);
sendtest.Send(null, "2", sign);
sign = new ManualResetEvent(false);
mre.Add(sign);
sendtest.Send(null, "3", sign);
foreach (ManualResetEvent item in mre)
{
sign.WaitOne();
}
richTextBox1.AppendText("处理完成!" + Environment.NewLine);

}
//更新界面
private void UpdateData(byte[] data, string type, ManualResetEvent Sign)
{
if (this.InvokeRequired)
{
//开关量
Sign.Set();
this.Invoke(OnDataUpdate, new object[] { data, type, Sign });
}
else
{
richTextBox1.AppendText("命令"+type+"处理完成!" + Environment.NewLine);
}
}
}
public class SendTest
{
public Form1 Owner;
public SendTest(Form1 owner)
{
this.Owner = owner;
}
//发送数据
public void Send(byte[] data, string type, ManualResetEvent item)
{
object[] paras = new object[] { data, type, item };
Thread threadStart = new Thread(new ParameterizedThreadStart(DataProcess));
threadStart.Start(paras);
}
//数据处理
private void DataProcess(object paras)
{
//参数列表
object[] list = paras as object[];
Thread.Sleep(1000);
Owner.OnDataUpdate(list[0] as byte[], list[1] as string, list[2] as ManualResetEvent);
}
}

有没有比较好的解决方法?
...全文
2610 13 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
wanghui0380 2017-10-31
  • 打赏
  • 举报
回复
Task[] ts=new Task[]{ TaskA,TaskB,TaskC} foreach t in ts var result=await t 可以保证他是按A,B,C执行的,这里的意思是虽然执行完成顺序有先有后,但是await结果是按你给定顺序操作的 另外TaskC里面,taskD,TaskC,需要这样声明 Task taskD=new Task(() => { }, TaskCreationOptions.AttachedToParent); TaskCreationOptions.AttachedToParent 附加到父线程里面,阻塞父线程,让父线程等待他执行完毕后再结束
wanghui0380 2017-10-31
  • 打赏
  • 举报
回复
开始处理---》命令1,命令2,命令3处理完成---》全部处理完成. 你主要是担心那个全部处理完成? 如果是task,我们可以task[].waitall. 对于子线程,我们则说你用线程他有join到父线程的,用task他有附加到父线程的,这个的含义就是子线程不执行完毕,父线程不会结束
wanghui0380 2017-10-31
  • 打赏
  • 举报
回复
以目前的net框架来说,这个实现起来最简单的方法是BlockingCollection<T> 因为这个也无需处理自己挂接处理列表变更事件,你只需要简单for each GetConsumingEnumerable()即可,有消息他自己会循环下去,没消息他自己会阻塞下去直到有数据为止 如果不知道BlockingCollection怎么用可以自己百度一下
rehuo 2017-10-31
  • 打赏
  • 举报
回复
还是不太明白呢,我就是通过委托去更新前台的,但是执行顺序不是我想要的,不考虑复杂的前置命令的问题,最先前的代码里面怎么才能实现正常的输出顺序?开始处理---》命令1,命令2,命令3处理完成---》全部处理完成。轮询?异步?这个都需要定义全局变量才可以实现吧
wanghui0380 2017-10-31
  • 打赏
  • 举报
回复
引用 6 楼 rehuo 的回复:
首先每个点(命令)都需要通知前台,比如说那个命令正在处理,有些点(命令)是需要前置命令完成以后才能进行下一步操作的,就像图上,两条短竖线(命令)上面的短竖线,这种前置命令处理比较简单,就是允许后面的命令可以执行的。2条横线是UI线程,需要中间的都处理完成以后,才可以进行下一步,不知道我说的清楚没?
如果是这种要求根本就不会产生任何困惑。一个队列足够了,你的线程根本就不需要管什么UI线程,直接把通知结果放队列里就可以了,UI线程自己从队列取结果 甚至在东西连队列都不需要,他可以是委托是事件,直接事件通知出去都成
  • 打赏
  • 举报
回复
多个比较耗费时间的任务需要并行执行,每个任务都需要通知UI线程,更新前台显示,等这些任务都执行完毕以后,然后UI线程再进行下一步操作 -》搜索 Task/Task.Wait/ContinueWith
rehuo 2017-10-31
  • 打赏
  • 举报
回复
首先每个点(命令)都需要通知前台,比如说那个命令正在处理,有些点(命令)是需要前置命令完成以后才能进行下一步操作的,就像图上,两条短竖线(命令)上面的短竖线,这种前置命令处理比较简单,就是允许后面的命令可以执行的。2条横线是UI线程,需要中间的都处理完成以后,才可以进行下一步,不知道我说的清楚没?
wanghui0380 2017-10-31
  • 打赏
  • 举报
回复
额,流程不明确,你就说你这个图是4个点,是每个点都通知,还是4个做玩了一起通知,还是说中间3个点完成了通知 每个点都通知,就是一个队列 还是4个做玩了一起通知,你可以把子线程附加的父线程 还是说中间3个点完成了通知,你可以waitall,然后在把后面新开的子线程附加到前面的线程 话说不管是线程还是现在的Task,都有很多重载去控制顺序和上下文的,玩这个玩意还是多看看人家微软有多少个方法,多少重载比较好 比如 Task.run,这个run还有N个重载呢
xdashewan 2017-10-31
  • 打赏
  • 举报
回复
参数ManualResetEvent Sign改成int行下标,内部使用mre[i].Set();
rehuo 2017-10-31
  • 打赏
  • 举报
回复
我的每个耗费时间的子线程里面都是有数据运算的,运算完成之后,需要将计算的结果更新到前台,不仅仅是提示用户;另外所有的子线程结束以后,UI线程还需要做下一步的处理,例如继续发送下一个命令,也不仅仅是更新前台,通知用户。如果使用UI线程轮询全局变量,子线程更新完成以后修改全局变量或者异步调用更新全局变量,到时可以实现,但是比较麻烦,因为我的子线程里面可能会再发起发送命令,这类似于大循环里面套小循环,有没有比较好的解决方案?
画图比较渣,大家谅解!
FainSheeg 2017-10-31
  • 打赏
  • 举报
回复
还可以提示用户,别让人瞎等。
FainSheeg 2017-10-31
  • 打赏
  • 举报
回复
UI上加个进度条呗,每新开一个线程进度条最大值加1,每完成一个,委托更新时候顺便更新进度条进度。进度完成了也就执行完了。
rehuo 2017-10-31
  • 打赏
  • 举报
回复
看来是我的思路有些问题,我是从子线程去更新UI界面的,不管是使用task还是thread,都不会达到我所要想的顺序,因为UI线程在阻塞的同时,子线程是不可能同步更新UI线程的。

17,748

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧