[简介]
常用网名: 猪头三
出生日期: 1981.XX.XX
QQ联系: 643439947
个人网站: 80x86汇编小站 https://www.x86asm.org
编程生涯: 2001年~至今[共22年]
职业生涯: 20年
开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python
开发工具: Visual Studio、Delphi、XCode、Eclipse、C++ Builder
技能种类: 逆向 驱动 磁盘 文件
研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全
项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测
[序言]
如果大家认真地阅读了"[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题"这篇文章, 就会发现里面的多线程同步机制是非常低效且愚蠢的. 那么如何解决这样的问题呢? 那就是利用"[原创][4]探究C#多线程开发细节-"初步体验ManualResetEvent类带来的同步效果""介绍的事件机制来处理这类棘手的问题.
[利用AutoResetEvent类来强制10个线程依次结束, 大概编程逻辑如下: ]
1> for循环创建每一个线程的时候, 为每个线程赋予一个索引号和AutoResetEvent类变量.
2> 为每一个线程对应的AutoResetEvent类变量放入队列ConcurrentQueue<T>中.
3> 当每个线程要结束之前, 都执行AutoResetEvent的WaitOne()等待.
通过上面的3步骤处理, 就可以达到10个线程依次结束效果.比如: 0号线程结束之后, 轮到1号线程结束. 1号线程结束之后, 轮到2号线程结束...依次类推.
[10个线程依次结束的过程中, 它们之间是如何响应的呢?]
假设如下情况:
1> 2号线程比1号线程提前准备进入终点, 但是在进入终点之前执行了WaitOne()等待, 目的就是等待1号线程是否已经进入终点了.
2> 此时1号线程没有进入终点, 那么2号线程会一直在终点前等待1号线程.
3> 当1号线程进入终点之后, 就针对2号线程的AutoResetEvent执行一次set(),通知2号线程, 我已经进入终点了, 轮到你进去了.
依次类推可以应用到其他线程的关系, 就是这简单的3步骤内部通信逻辑, 就能让0号线程~9号线程, 有序的步入终点(即结束线程任务).
[下面是一套完整的代码]
这里要特别理解这2行代码
AutoResetEvent event_Next = mpr_cq_ThreadEvent.ToArray()[mpu_int_ThreadIndex + 1];
event_Next.Set();
public partial class Form_Main : Form{private ConcurrentQueue<AutoResetEvent> mpr_cq_ThreadEvent = new ConcurrentQueue<AutoResetEvent>();public class Thread_Run{public int mpu_int_ThreadIndex;private Action<int> mpr_action_UpdateWaiteInfo;private ConcurrentQueue<AutoResetEvent> mpr_cq_ThreadEvent;private AutoResetEvent mpr_event_State;public Thread_Run(Action<int> action_param_UpdateWaiteInfo, ref ConcurrentQueue<AutoResetEvent> cq_param_ThreadEvent, object obj_param_EventState){mpr_action_UpdateWaiteInfo = action_param_UpdateWaiteInfo;mpr_cq_ThreadEvent = cq_param_ThreadEvent;mpr_event_State = (AutoResetEvent)obj_param_EventState;}public int mpu_fun_ShowIndex(){return mpu_int_ThreadIndex;}public void mpu_pro_StartThread(){Thread class_Thread = new Thread(Thread_Exe);class_Thread.Start();}private void Thread_Exe(){if (mpu_int_ThreadIndex != 0){// 如果不是第一个线程则直接等待mpr_event_State.WaitOne();}//调用委托方法来更新UImpr_action_UpdateWaiteInfo?.Invoke(mpu_int_ThreadIndex);// 通知当前线程的下一个线程放弃等待,可直接返回// 比如当前是1号线程,那么它的下一个就是2号线程if (mpu_int_ThreadIndex + 1 < mpr_cq_ThreadEvent.Count()){AutoResetEvent event_Next = mpr_cq_ThreadEvent.ToArray()[mpu_int_ThreadIndex + 1];event_Next.Set();}}}// End Thread_Run()public Form_Main(){InitializeComponent();}public void mpu_pro_UpdateWaiteInfo(int int_param_ThreadIndex){if (InvokeRequired){this.Invoke((MethodInvoker)delegate {lb_WaitInfo.Text += (Environment.NewLine + string.Format("{0} 号线程已创建成功.", int_param_ThreadIndex));});}}private void Bn_StartThread_Click(object sender, EventArgs e){// 启动10个线程for (int int_Index = 0; int_Index < 10; int_Index++){var var_ThreadEvent = new AutoResetEvent(false);mpr_cq_ThreadEvent.Enqueue(var_ThreadEvent);Thread_Run class_ThreadRun = new Thread_Run(mpu_pro_UpdateWaiteInfo, ref mpr_cq_ThreadEvent, var_ThreadEvent);class_ThreadRun.mpu_int_ThreadIndex = int_Index;class_ThreadRun.mpu_pro_StartThread();}}}
[结尾]
这份代码的完美度达到了95%, 但还有更完美的写法, 就是利用ConcurrentDictionary<T>类来代替ConcurrentQueue<T>类, 并管理AutoResetEvent事件. 下一篇我们将会继续优化代码