★前言
打开久违的Live Writer,又已经好久没写博客了,真的太懒了。废话不多说了,直接进入这次博客的主题--Timer。为什么要写这个呢,因为前几天应朋友之邀,想做个“黑客”小工具,功能挺简单就是自动获取剪贴板的内容然后发送邮件,就需要用到Timer来循环获取剪贴板的内容,但是由于到了发送邮件这个功能,使用C#的SmtpClient始终发送不了邮件,以前写过类似发邮件的功能,当时可以用网易的,现在也不能用了,不知道咋回事,只好作罢。在使用Timer中遇到了之前没有想过的问题--重入。
★介绍
首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件。官方介绍在这里,摘抄如下:
Timer 组件是基于服务器的计时器,它使您能够指定在应用程序中引发 Elapsed 事件的周期性间隔。然后可通过处理这个事件来提供常规处理。 例如,假设您有一台关键性服务器,必须每周 7 天、每天 24 小时都保持运行。 可以创建一个使用 Timer 的服务,以定期检查服务器并确保系统开启并在运行。 如果系统不响应,则该服务可以尝试重新启动服务器或通知管理员。 基于服务器的 Timer 是为在多线程环境中用于辅助线程而设计的。 服务器计时器可以在线程间移动来处理引发的 Elapsed 事件,这样就可以比 Windows 计时器更精确地按时引发事件。
如果想了解跟其他的timer有啥区别,可以看这里,里面有详细的介绍,不再多说了(其实我也不知道还有这么多)。那使用这个计时器有啥好处呢?主要因为它是通过.NET Thread Pool实现的、轻量、计时精确、对应用程序及消息没有特别的要求。
★使用
下面就简单介绍一下,这个Timer是怎么使用的,其实很简单,我就采用微软提供的示例来进行测试,直接上代码了:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 |
//Timer不要声明成局部变量,否则会被GC回收 private static System.Timers.Timer aTimer; public static void Main() { //实例化Timer类,设置间隔时间为10000毫秒; aTimer = new System.Timers.Timer(10000); //注册计时器的事件 aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); //设置时间间隔为2秒(2000毫秒),覆盖构造函数设置的间隔 aTimer.Interval = 2000; //设置是执行一次(false)还是一直执行(true),默认为true aTimer.AutoReset = true ; //开始计时 aTimer.Enabled = true ; Console.WriteLine( "按任意键退出程序。" ); Console.ReadLine(); } //指定Timer触发的事件 private static void OnTimedEvent( object source, ElapsedEventArgs e) { Console.WriteLine( "触发的事件发生在: {0}" , e.SignalTime); } |
运行的结果如下,计时蛮准确的:
?
1
2
3
4
5
6
7
8 |
/* 按任意键退出程序。 触发的事件发生在: 2014/12/26 星期五 23:08:51 触发的事件发生在: 2014/12/26 星期五 23:08:53 触发的事件发生在: 2014/12/26 星期五 23:08:55 触发的事件发生在: 2014/12/26 星期五 23:08:57 触发的事件发生在: 2014/12/26 星期五 23:08:59 */ |
★重入问题重现及分析
什么叫重入呢?这是一个有关多线程编程的概念:程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据不一致的情况。Timer方法重入是指使用多线程计时器,一个Timer处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。下面演示一下重入问题的产生(可能重现的不是很好,不过也能简单一下说明问题了):
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 |
//用来造成线程同步问题的静态成员 private static int outPut = 1; //次数,timer没调一次方法自增1 private static int num = 0; private static System.Timers.Timer timer = new System.Timers.Timer(); public static void Main() { timer.Interval = 1000; timer.Elapsed += TimersTimerHandler; timer.Start(); Console.WriteLine( "按任意键退出程序。" ); Console.ReadLine(); } /// /// System.Timers.Timer的回调方法 /// /// /// private static void TimersTimerHandler( object sender, EventArgs args) { int t = ++num; Console.WriteLine( string .Format( "线程{0}输出:{1}, 输出时间:{2}" , t, outPut.ToString(),DateTime.Now)); System.Threading.Thread.Sleep(2000); outPut++; Console.WriteLine( string .Format( "线程{0}自增1后输出:{1},输出时间:{2}" , t, outPut.ToString(),DateTime.Now)); } |
![]() | ![]() .. 定价:¥133 优惠价:¥133.0 更多书籍 |
![]() | ![]() .. 定价:¥124 优惠价:¥124.0 更多书籍 |