[简介]
常用网名: 猪头三
出生日期: 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()一次操作.
[结尾]
这次内容看起来很简单, 但是必须要用心体会到它的工作原理和效果, 只有体验到了同步效果, 才会写出更好的多线程并发程序. 大家如果阅读完这篇文章, 有更多疑问可以留言, 有更好的建议和想法,也可以留下你的评论.
原文地址:https://blog.csdn.net/Code_GodFather/article/details/134770035
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_50168.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!