[原创][5]探究C#多线程开发细节-利用AutoResetEvent类解决多线程循环轮询假同步的问题.

[简介]
常用网名: 猪头三
出生日期: 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();
                }

                //调用委托方法来更新UI
                mpr_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事件. 下一篇我们将会继续优化代码

相关推荐

  1. C语言线编程-线同步

    2023-12-07 10:28:07       34 阅读
  2. c# 线创建及线同步

    2023-12-07 10:28:07       22 阅读
  3. C++ 线

    2023-12-07 10:28:07       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-07 10:28:07       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-07 10:28:07       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-07 10:28:07       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-07 10:28:07       18 阅读

热门阅读

  1. 生活、工作常用API免费接口

    2023-12-07 10:28:07       25 阅读
  2. 梦想与魔法:编程之路的挑战与荣耀

    2023-12-07 10:28:07       28 阅读
  3. 5-redis高级-哨兵

    2023-12-07 10:28:07       32 阅读
  4. MacOS查看JDK版本或卸载

    2023-12-07 10:28:07       27 阅读
  5. Kubernetes+istio部署bookinfo、Online boutique和sock shop

    2023-12-07 10:28:07       33 阅读
  6. ios 逆向分分析,某业帮逆向算法(二)

    2023-12-07 10:28:07       38 阅读