本文介绍: 为了优化“[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题“”文章里面代码示例, 需要专门为”ManualResetEvent类”写一篇文章. 只有解了”ManualResetEvent类”的作用, 才会知道如何优化.

[简介]
常用网名: 猪头三
生日期: 1981.XX.XX
个人网站: 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>解决多线程的无顺序性的问题“-CSDN博客文章里面代码示例, 需要专门为”ManualResetEvent类”写一篇文章. 只有解了“ManualResetEvent类”作用, 才会知道如何优化

[为什么优化“[原创][3]探究C#多线程开发细节-“用ConcurrentQueue<T>解决多线程的无顺序性的问题“”文章里面的代码示例?]
如果认真阅读了代码, 就会发现, 在进行多线程同步时候, 竟然使用for循环+Sleep()组合实现轮询. 这是非常不友好的行为. 这里一个弊端:for循环会不断的消耗CPU资源, 虽然通过Sleep(5)这样极短的休眠时间降低CPU的使用率, 但仅仅是给软件使用者造成一种假象. 但实际上, 把时间放大到1秒钟, 这个for循环执行200次, 给CPU的负担也不小的.

[为了避免for循环+Sleep()这样初级的写法, 可以使用ManualResetEvent解决.]
那么ManualResetEvent类的作用效果是如何的呢?可以把ManualResetEvent类看作是一个红绿灯, 当ManualResetEvent类处于红灯状态时候, 线程执行等待, 不允许执行. 当ManualResetEvent类处于绿灯状态, 线程恢复执行状态, 继续上一次操作. 好比现实中的红绿灯过马路的效果.下面简单看看ManualResetEvent类的使用方法

1>  ManualResetEvent event_ControlThread = new ManualResetEvent(false); // 创建一个ManualResetEvent类, 并设置false(即红灯状态)
2>  event_ControlThread.WaitOne(); // 等待阻塞. 如果是红灯状态, 该代码就阻塞着, 不给线程执行event_ControlThread.WaitOne()之后的任何代码. 反之, 绿灯状态, 线程可以继续往下执行.
3> event_ControlThread.Reset();   // 等当前状态是处于绿灯状态的时候, 如果恢复为红灯状态, 那就执行一次Reset()操作.
4>  event_ControlThread.Set();     // 如果当前状态处于红灯状态, 通过Set()一次, 就会变成绿灯状态, 随后绿灯灭掉. 最终的效果就是灯灭了. 因此为了保持灯处于亮灯状态, 一定要通过Reset()操作复原.

[如果理解上面的所说的, 可以尝试一个例子]
1> 启动Visual Studio Enterprise 2022版本
2> 建立一个C# Windows窗体应用(.NET Framework). 
3> 然后窗体上放上两个按钮一个Lable控件
4> 按钮1  : 启动一个带有for循环的线程, 然后这个for循环可以针对变量int_Count进行+1操作
5> 按钮2 : 调用event_ControlThread.Set()处理, 每单击一次, for循环线程才能运行一次.
完成上面的步骤之后, 模仿下面的代码, 抄写到你建立的项目中.

    public partial class Form_Event_Demo : Form
    {
        private int mpr_int_Count = 0;
        // private AutoResetEvent event_ControlThread = new AutoResetEvent(false);
        private ManualResetEvent event_ControlThread = new ManualResetEvent(false); // 创建事件初始化为红灯状态

        public Form_Event_Demo()
        {
            InitializeComponent();
        }

        // 启动循环 +1 线程
        private void Bn_StartThread_Click(object sender, EventArgs e)
        {
            Thread class_LoopThread = new Thread(() =>
            {
                for (int int_Index = 0; int_Index < 10; int_Index++)
                {
                    event_ControlThread.WaitOne(); // 等待事件信号(即等待亮绿灯)

                    mpr_int_Count++;

                    // 界面显示结果
                    if (lb_Result.InvokeRequired)
                    {
                        this.Invoke((MethodInvoker)delegate {

                            lb_Result.Text = $"当前结果: {mpr_int_Count}";

                        });
                    }
                    else
                    {
                        lb_Result.Text = $"当前结果: {mpr_int_Count}";
                    }

                    event_ControlThread.Reset(); // 手动重置信号(即把灭灯状态恢复为红灯状态)
                }
            });
            class_LoopThread.Start();

        }// End Bn_StartThread_Click()

        private void Bn_Increment_Click(object sender, EventArgs e)
        {
            event_ControlThread.Set(); //设置信号(即把红灯切换为绿灯, 然后再灭灯), 通知线程执行一次循环
        }// End Bn_Increment_Click()

    }

[代码还可以在优化一下, ManualResetEvent()可以替换为AutoResetEvent(), 这样更加自动化]
AutoResetEvent()的好处就是, 如果灭灯状态, 它会自动帮你恢复为亮灯状态, 而不需要手工去Reset()一次操作.

[结尾]
这次内容看起来很简单, 但是必须要用心体会到它的工作原理效果, 只有体验到了同步效果, 才会写出更好多线程并发程序. 大家如果阅读完这篇文章, 有更多疑问可以留言, 有更好建议和想法,也可以留下你的评论.  

[效果演示]

初步体验ManualResetEvent类带来的同步效果

原文地址:https://blog.csdn.net/Code_GodFather/article/details/134770035

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_50168.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注