关于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 ...
随机推荐
- map初步(由ABBC--->A2BC)
1.题目: Given a string containing only 'A' - 'Z', we could encode it using the following method: 1. Ea ...
- java -cp 用法介绍
java -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,window上分号“;” 分隔,linux上是分号“:”分隔.不支持通 ...
- Swift 循环
循环类型 Swift 语言提供了以下几种循环类型.点击链接查看每个类型的详细描述: 循环类型 描述 for-in 遍历一个集合里面的所有元素,例如由数字表示的区间.数组中的元素.字符串中的字符. fo ...
- scikit-learn机器学习(四)使用决策树做分类
我们使用决策树来创建一个能屏蔽网页横幅广告的软件. 已知图片的数据判断它属于广告还是文章内容. 数据来自 http://archive.ics.uci.edu/ml/datasets/Internet ...
- MATLAB绘图及例子总结
MATLAB绘图及例子总结 二维图 例 1 X1=[1,2,4,6,7,8,10,11,12,14,16,17,18,20]; Y1=[1,2,4,6,7,8,10,10,8,7,6,4,2,1]; ...
- 【计算机视觉】双目测距(六)--三维重建及UI显示
原文: http://blog.csdn.NET/chenyusiyuan/article/details/5970799 在获取到视差数据后,利用 OpenCV 的 reProjectImageTo ...
- 关于Angular+ngx-perfect-scrollbar自定义各大浏览器滚动条样式的解决方法
资料: http://manos.malihu.gr/jquery-custom-content-scroller/ (此项是结合Jquery使用的,在此并未采用) https://www.npmj ...
- linux用户管理添加用户的默认配置文件useradd详解
/etc/default/useradd 文件 cat /etc/default/useradd 常用命令: useradd 添加用户 userdel 删除用户 passwd 改密码 use ...
- 提取json字符串中指定格式中的参数值
直接上代码: import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; p ...
- Python非递归实现二叉树的后续遍历
leetcode 145. Binary Tree Postorder Traversal 思路一: 使用一个栈stack保存经过的根结点,另一个栈flag保存每个结点的右子树是否遍历: 如果根结点存 ...