欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

关于ManualResetEvent的实例分析

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

最近用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<object, object> callbackevent;  //回调
        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();
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer_elapsed(object sender, eventargs e)
        {
            try
            {
                timerevent.set(); //调用 set()方法 manualresetevent 处于终止状态waitone不会阻塞线程会一直运行下去
            }
            catch
            {
                ;
            }
        }

        /// <summary>
        /// 当调用 set()方法 manualresetevent 处于终止状态waitone不会阻塞线程会一直运行下去
        /// 当调用 reset()方法manualresetevent处于非终止状态waitone会阻塞线程直到再调用set()方法
        /// </summary>
        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,挺好。