最近用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,挺好。

关于ManualResetEvent的实例分析的更多相关文章

  1. RPC原理及RPC实例分析

    在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...

  2. java基础学习05(面向对象基础01--类实例分析)

    面向对象基础01(类实例分析) 实现的目标 1.如何分析一个类(类的基本分析思路) 分析的思路 1.根据要求写出类所包含的属性2.所有的属性都必须进行封装(private)3.封装之后的属性通过set ...

  3. (转)实例分析:MySQL优化经验

    [IT专家网独家]同时在线访问量继续增大,对于1G内存的服务器明显感觉到吃力,严重时甚至每天都会死机,或者时不时的服务器卡一下,这个问题曾经困扰了我半个多月.MySQL使用是很具伸缩性的算法,因此你通 ...

  4. sql注入实例分析

    什么是SQL注入攻击?引用百度百科的解释: sql注入_百度百科: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具 ...

  5. 实例分析ELF文件静态链接

    参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第4章 静态链接 开发平台: [thm@tanghuimin static_link]$ uname ...

  6. 用实例分析H264 RTP payload

    用实例分析H264 RTP payload H264的RTP中有三种不同的基本负载(Single NAL,Non-interleaved,Interleaved) 应用程序可以使用第一个字节来识别. ...

  7. nodejs的模块系统(实例分析exprots和module.exprots)

    前言:工欲善其事,必先利其器.模块系统是nodejs组织管理代码的利器也是调用第三方代码的途径,本文将详细讲解nodejs的模块系统.在文章最后实例分析一下exprots和module.exprots ...

  8. Android Touch事件原理加实例分析

    Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. ...

  9. Camera图像处理原理及实例分析-重要图像概念

    Camera图像处理原理及实例分析 作者:刘旭晖  colorant@163.com  转载请注明出处 BLOG:http://blog.csdn.net/colorant/ 主页:http://rg ...

随机推荐

  1. docker-compose ELK+Filebeat查看docker及容器的日志

    我目前所在公司开发团队比较小,为集团下面的工厂开发了一套小的系统,跑在一台CentOS服务器上,服务器搭建了docker环境,安装了docker-compose,但在日志处理方面,暂时没有一个好的方法 ...

  2. qt 创建及调用QT的 DLL

    先讲一下对QT动态链接库的调用方法,主要包括: 1.显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法 2.显示链接DLL,调用DLL中类对象.成员函数.(通过对象即可实现类成员函数 ...

  3. DNS -- 快速清除DNS缓存

    MAC: sudo dscacheutil -flushcache Linux: dnsmasq的是一个轻量级的DNS.TFTP和DHCP服务器.它的目的是给局域网提供配对的DNS和DHCP服务. d ...

  4. linux系统安装Memcache

    Linux系统安装memcached 首先要先安装libevent库. centos  下执行 yum install libevent libevent-devel 查看memcached 是否已经 ...

  5. Editplus的运行JAVA的配置

    工具--->参数设置

  6. Centos7.4.1708安装Jumpserver

    Jumpserver 环境要求:硬件配置: 2个CPU核心, 4G 内存, 50G 硬盘(最低)操作系统: Linux 发行版 x86_64Python = 3.6.xMysql Server ≥ 5 ...

  7. python图论包networks(最短路,最小生成树带包)

    官方文档: https://networkx.github.io/documentation/networkx-1.10/reference/algorithms.html 最短路和最小生成树: im ...

  8. 提取站长之家IP批量查询

    1.工具说明 写报告的时候为了细致性,要把IP地址对应的地区给整理出来.500多条IP地址找出对应地区复制粘贴到报告里整了一个上午. 为了下次更好的完成这项重复性很高的工作,所以写了这个小的脚本. 使 ...

  9. CSS - clearfix清除浮动

    首先,我们来解释一下为什么要使用 clearfix(清除浮动). 通常我们在写html+css的时候,如果一个父级元素内部的子元素是浮动的(float),那么常会发生父元素不能被子元素正常撑开的情况, ...

  10. HANA到MySQL数据同步方法!

    随着各行各业信息化建设的不断发展,异构数据库间的互通.汇聚,挖掘,分析逐渐被提上日程, TreeSoft数据库管理系统,实现了异构数据库的维护.监控.可视化.自动交换同步.目前支持MySQL,Orac ...