博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于ManualResetEvent的实例分析
阅读量:5366 次
发布时间:2019-06-15

本文共 5565 字,大约阅读时间需要 18 分钟。

最近用WPF开发时使用多个定时器处理时需要实例化N多个DispatcherTimer,而且全部暴露在程序外部,显得很冗杂,例如下面的例子:用到的两个定时器就要实例化两个DispatcherTimer,不知道各位看的想不想吐,但是我i是觉得这样很恶心,下面就是两个实例化的定时器。

            //定时器1

            System.Windows.Threading.DispatcherTimer readDataTimer = new System.Windows.Threading.DispatcherTimer();

            readDataTimer.Tick += new EventHandler(TimeCycle);

            readDataTimer.Interval = new TimeSpan(0,0,10,0);
            readDataTimer.Start();

           //定时器2

           System.Windows.Threading.DispatcherTimer readDataTimer_TW = new System.Windows.Threading.DispatcherTimer();

            readDataTimer_TW.Tick += new EventHandler(TimeCycle_TW);

            readDataTimer_TW.Interval = new TimeSpan(0, 0, 120, 0);
            readDataTimer_TW.Start();

  OK,引导的部分结束,下面我们就来谈谈ManualResetEvent是个什么东西,能够带给我们什么便利之处。

   说白了ManualResetEvent就是一个实现线程之间的相互通信的东东,其中很重要的几个角色给大家列举一下:

    1. ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则非终止状态为 false

    2.Waitone() ; ManualResetEvent 处于非终止状态WaitOne会阻塞线程,ManualResetEvent 处于终止状态Waitone()无作用,线程会一直执行。

    3.Set() ;         ManualResetEvent 处于非终止状态WaitOne会阻塞线程的话, 当调用 Set()方法会允许线程继续执行下去。 

    4.Reset();      线程继续后,当调用 Reset()方法 ManualResetEvent处于非终止状态WaitOne会阻塞线程直到再调用Set()方法,

 

  OK,介绍到这里,基本的知识应该掌握了吧,下面我们回归到开篇提到的案例,我们来封装一个定时器类;用到的知识点就是刚介绍的。

  首先我们新建一个类吧,就叫它MyThreadTimer,好不好;

   首先在MyThreadTimer定义几个字段分别定义定时器,线程,及回调

        private Thread timerThread;   //线程

        private System.Timers.Timer timer;   //定时器
        private System.Threading.ManualResetEvent timerEvent;    
        public event CallBackEventHandle<object, object> callBackEvent;  //回调

  好,准备就绪,我们来创建一个构造函数包括的参数有3个分别如下

     public MyThreadTimer(int TimerCount ,CallBackEventHandle<object, object> eventFunc, bool startSign)

        {
            this.timerEvent = new ManualResetEvent(false);  //处于非终止状态   初始阻塞
            //定时器一直运行
            this.timer = new System.Timers.Timer();
            this.timer.Interval = TimerCount;
            this.timer.Elapsed += timer_Elapsed;
            //创建线程
            this.timerThread = new Thread(timerThreadFunc);
            this.timerThread.IsBackground = true;

            callBackEvent += eventFunc; //订阅响应方法
            if (startSign)
            {
                this.timer.Start();
                this.timerThread.Start();
            }
        }

看到构造函数大家也就差不多看的八九不离十了吧,构造函数中实例了一个定时器,一个线程,还有一个就是订阅了定时器的响应函数,下面慢慢给大家介绍这几个方法的作用。

首先给大家介绍的定时器的作用,先把定时器的执行方法给出。

       private void timer_Elapsed(object sender, EventArgs e)

        {
            try
            {
                timerEvent.Set(); //调用 Set()方法 ManualResetEvent 处于非终止状态WaitOne不会阻塞线程会一直运行下去
            }
            catch
            {
                ;//自己怎么喜欢怎么记异常
            }
        }

大家看到就一条语句timerEvent.Set(),这个就是调用 Set()方法 ManualResetEvent 处于非终止状态WaitOne不会阻塞线程会一直运行下去(可以看成这个方法把ManualResetEvent弄成了终止状态了)

大家先记住就好了(基本的作用要牢记);

再来说说线程执行的方法,还是先把方法给出后再来分析

  private void timerThreadFunc()

        {
            try
            {
                while (true)
                {
                    timerEvent.WaitOne();//如果处于终止状态就不会阻塞,处于非终止状态就阻塞
                    timerEvent.Reset();
                    if (this.callBackEvent != null)
                    {
                        this.callBackEvent(this, EventArgs.Empty);
                    }
                }
            }
            catch(Exception ex)
            {
            }
        }

  这里可以看到,线程执行机会进入一个while循环,因为ManualResetEvent初始化的状态为Fasle(非终止状态),遇到WaitOne就阻塞了,但是还记得上面的定时器吗,timerEvent.Set()就会打破这个僵局,线程就会继续的执行下去了。继续向下看程序  timerEvent.Reset();这时ManualResetEvent又被Reset()设置成遇到Waitone()会阻塞了。说到这里想向大家应该知道这个是啥意思了吧。好了,我封的定时类贴出来吧,分享一下(大神绕道,哈哈);

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Threading;using System.Windows;namespace Common{   public class MyThreadTimer    {        /*         ManualResetEvent可以通知一个或多个正在等待的线程已发生事件,允许线程通过发信号互相通信,来控制线程是否可心访问资源         当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态。        此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。        一旦它被终止,ManualResetEvent 将保持终止状态,直到它被手动重置。即对 WaitOne 的调用将立即返回。        */        //成员变量        private Thread timerThread;   //线程        private System.Timers.Timer timer;   //定时器        private System.Threading.ManualResetEvent timerEvent;            public event CallBackEventHandle
callBackEvent; //回调 public MyThreadTimer(int TimerCount ,CallBackEventHandle
eventFunc, bool startSign) { this.timerEvent = new ManualResetEvent(false); //处于非终止状态 初始阻塞 //定时器一直运行 this.timer = new System.Timers.Timer(); this.timer.Interval = TimerCount; this.timer.Elapsed += timer_Elapsed; //创建线程 this.timerThread = new Thread(timerThreadFunc); this.timerThread.IsBackground = true; callBackEvent += eventFunc; //订阅响应方法 if (startSign) { this.timer.Start(); this.timerThread.Start(); } } ///
/// /// ///
///
private void timer_Elapsed(object sender, EventArgs e) { try { timerEvent.Set(); //调用 Set()方法 ManualResetEvent 处于终止状态WaitOne不会阻塞线程会一直运行下去 } catch { ; } } ///
/// 当调用 Set()方法 ManualResetEvent 处于终止状态WaitOne不会阻塞线程会一直运行下去 /// 当调用 Reset()方法ManualResetEvent处于非终止状态WaitOne会阻塞线程直到再调用Set()方法 /// private void timerThreadFunc() { try { while (true) { timerEvent.WaitOne();//如果处于终止状态就不会阻塞,处于非终止状态就阻塞 timerEvent.Reset(); if (this.callBackEvent != null) { this.callBackEvent(this, EventArgs.Empty); } } } catch(Exception ex) { } } }}

 调用就很简单了

            MyThreadTimer myth = new MyThreadTimer(1000, f, true);

            int i = 0;
             private void f(object sender, object args)
            {
              i++;
            }

  虽然还是需要实例化N个定时类,但是起码显得整洁多了,顺便也介绍下ManualResetEvent,挺好。

转载于:https://www.cnblogs.com/TechnologyDictionary/p/10972394.html

你可能感兴趣的文章
iView组件样式修改
查看>>
Libre 6006 「网络流 24 题」试题库 / Luogu 2763 试题库问题 (网络流,最大流)
查看>>
对于在git上面拉代码报"error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054"解决方法...
查看>>
jQuery TextBox用法
查看>>
分布式架构之美~
查看>>
Java编程思想:内部类基础部分
查看>>
了解html
查看>>
Git命令cherry-pick,选择把一部分代码提交到另一个分支
查看>>
Mysql优化_内置profiling性能分析工具
查看>>
设置时间属性
查看>>
【分享】开发者必备平台汇总
查看>>
Json填充Object工具
查看>>
【BZOJ 3534】: [Sdoi2014]重建
查看>>
改进基于优先队列的最短路径搜索『洪水流思想的体现』
查看>>
RStudio版本号管理 整合Git
查看>>
Java中的枚举类为何不能有public构造器
查看>>
2016.3.4(反射)
查看>>
增加或删除父视图--但仍要保留原来相对布局
查看>>
CSS基础知识2
查看>>
Asp.net在服务器端读取Excel文件所需要做的事情
查看>>