C# ManualResetEvent 类分析

C# ManualResetEvent 类分析

官方解释

链接: 微软官方文档

1. 需求

你可能有这样一种需求:有一个重复的或者耗时长的工作线程,界面有一个暂停按钮,当你按下的时候,期望工作线程能暂停一下.当你在界面按下继续按钮的时候,期望工作线程能从刚刚停下的那一刻重新开始工作.

1.1 创造一个虚拟的需求

我希望有一个界面,后台重复每秒刷新时间,一个暂停按钮,一个继续按钮.
在这里插入图片描述

1.2 V1.0 版本

用一个静态变量去控制更新时间的线程,当点击暂停时,时间停止更新,点击继续时,时间继续跳动.开启了一个线程,将更新时间的函数放置在一个while循环里,可以打开任务管理器看到,CPU占用率直接干到10%以上.无论是点击暂停还是继续按钮,实际上这个线程CPU一直在开销,于是我们有了一个新需求...
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ManualResetEvent
{
    public partial class Form1 : Form
    {
        private static bool Pause = false;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                while(true)
                {
                    if(Pause)
                    {
                        continue;
                    }
                    label1.Invoke(new Action(() =>
                    {
                        var time = DateTime.Now;
                        label1.Text = time.ToString("yyyy年MM月dd日 HH:mm:ss");
                    }));
                }
            });
        }

        private void btn_Pause_Click(object sender, EventArgs e)
        {
            Pause = true;
        }

        private void btn_Continue_Click(object sender, EventArgs e)
        {
            Pause = false;
        }
    }
}

1.3 V1.1 版本

被暂停时, 线程处于休眠状态, 不占用CPU,让CPU休息一下.
于是用ManualResetEvent替代V1.0版本简单的布尔量.
可以看到,当正常更新时间,CPU占用跟以前一样,但是当按下暂停键的时候,CPU占用率几乎为0!
未暂停状态
暂停状态

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ManualResetEvent
{
    public partial class Form1 : Form
    {
        //private static bool Pause = false;
        private static System.Threading.ManualResetEvent m_WaitHandle = new System.Threading.ManualResetEvent(true);
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                while(true)
                {
                    //if (Pause)
                    //{
                    //    continue;
                    //}
                    m_WaitHandle.WaitOne();
                    label1.Invoke(new Action(() =>
                    {
                        var time = DateTime.Now;
                        label1.Text = time.ToString("yyyy年MM月dd日 HH:mm:ss");
                    }));
                }
            });
        }
        //暂停
        private void btn_Pause_Click(object sender, EventArgs e)
        {
            //Pause = true;
            m_WaitHandle.Reset();
        }
        //继续
        private void btn_Continue_Click(object sender, EventArgs e)
        {
            //Pause = false;
            m_WaitHandle.Set();
        }
    }
}

2. 分析

2.1 WaitOne阻止当前线程

当程序执行到WaitOne方法时,将判断ManualResetEvent是否有信号,有信号时不阻塞,没信号时阻塞,WaitOne后面的语句将暂停执行.

2.2 Set设置信号, 亮绿灯

Set方法将通知其他线程的WaitOne,继续执行后面的语句.

2.3 Reset重置信号, 亮红灯

Reset方法将使其他线程的WaitOne阻塞.

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值