关于ManualResetEvent的实例分析
最近用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的实例分析的更多相关文章
- RPC原理及RPC实例分析
在学校期间大家都写过不少程序,比如写个hello world服务类,然后本地调用下,如下所示.这些程序的特点是服务消费方和服务提供方是本地调用关系. 1 2 3 4 5 6 public class ...
- java基础学习05(面向对象基础01--类实例分析)
面向对象基础01(类实例分析) 实现的目标 1.如何分析一个类(类的基本分析思路) 分析的思路 1.根据要求写出类所包含的属性2.所有的属性都必须进行封装(private)3.封装之后的属性通过set ...
- (转)实例分析:MySQL优化经验
[IT专家网独家]同时在线访问量继续增大,对于1G内存的服务器明显感觉到吃力,严重时甚至每天都会死机,或者时不时的服务器卡一下,这个问题曾经困扰了我半个多月.MySQL使用是很具伸缩性的算法,因此你通 ...
- sql注入实例分析
什么是SQL注入攻击?引用百度百科的解释: sql注入_百度百科: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具 ...
- 实例分析ELF文件静态链接
参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第4章 静态链接 开发平台: [thm@tanghuimin static_link]$ uname ...
- 用实例分析H264 RTP payload
用实例分析H264 RTP payload H264的RTP中有三种不同的基本负载(Single NAL,Non-interleaved,Interleaved) 应用程序可以使用第一个字节来识别. ...
- nodejs的模块系统(实例分析exprots和module.exprots)
前言:工欲善其事,必先利其器.模块系统是nodejs组织管理代码的利器也是调用第三方代码的途径,本文将详细讲解nodejs的模块系统.在文章最后实例分析一下exprots和module.exprots ...
- Android Touch事件原理加实例分析
Android中有各种各样的事件,以响应用户的操作.这些事件可以分为按键事件和触屏事件.而Touch事件是触屏事件的基础事件,在进行Android开发时经常会用到,所以非常有必要深入理解它的原理机制. ...
- Camera图像处理原理及实例分析-重要图像概念
Camera图像处理原理及实例分析 作者:刘旭晖 colorant@163.com 转载请注明出处 BLOG:http://blog.csdn.net/colorant/ 主页:http://rg ...
随机推荐
- ubantu 安装boost库 c++connector
安装libmysqlcppconn: sudo apt-get install libmysqlcppconn-dev 安装libboost: sudo apt-get install libboos ...
- 源码编译vi过程中进行配置时报“checking if compile and link flags for Python are sane... no: PYTHON DISABLED”怎么办?
答: 需要安装python开发库(如果不安装这个库,那么在配置时执行./configure --enable-pythoninterp=yes将不会生效,以至于vi的python特性并没有被开启) 如 ...
- Swift 可选(Optionals)类型
Swift 的可选(Optional)类型,用于处理值缺失的情况.可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值". Swfit语言定义后缀?作为命 ...
- java+断点续传
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 先说下要求: PC端全平台支持,要求支持Windows,Mac,Linux 支持所 ...
- iOS自适应行高方法及问题
最近一周被项目的动态高度虐的很惨,感觉浪费了很多时间,但是值得高兴的是对动态高度的使用掌握了好多方法,并且知道了方法之间的区别和优缺点. 1.最常用的: UITableView+FDTemplateL ...
- C#使用MPI进行高性能计算
MPI.NET是用于Microsoft.NET环境的高性能.易于使用的消息传递接口(MPI)实现.mpi是编写在分布式内存系统(如计算集群)上运行的并行程序的事实上的标准,并且得到了广泛的实现.大多数 ...
- Lua中用table统一管理需要获取的unity物体
unity上的组件,可以用table统一管理 然后在初始化时候统一给table赋值,这样需要用到时候直接调用table中对应的key便可拿到对应的物体,省下了在脚本开头一堆声明的脚本,这样就不用声明这 ...
- centos7安装过程中的安装源设置
centos7的安装源设置:http://mirrors.aliyun.com/centos/7/os/x86_64/
- jquery+flask+keras+nsfw快速搭建一个简易鉴黄工具
1. demo 地址:http://www.huchengchun.com:8127/porn_classification 接口说明: 1. http://www.huchengchun.com:8 ...
- 2019-10-17 李宗盛 spss作业
开放数据库连接是为解决异构数据库之间的数据共享而产生的,现已成为Wosa cwindows开放系统体系结构主要部分和基于Windows环境的一种数据库访问接口标准ODBS被异构数据库访问提供统一接口, ...