C#中Timer使用及解决重入问题
2015-12-09 16:44
417 查看
[摘要]本文是对C#中Timer使用及解决重入问题的讲解,对学习C#编程技术有所帮助,与大家分享。
★前言
打开久违的Live Writer,又已经好久没写博客了,真的太懒了。废话不多说了,直接进入这次博客的主题--Timer。为什么要写这个呢,因为前几天应朋友之邀,想做个“黑客”小工具,功能挺简单就是自动获取剪贴板的内容然后发送邮件,就需要用到Timer来循环获取剪贴板的内容,但是由于到了发送邮件这个功能,使用C#的SmtpClient始终发送不了邮件,以前写过类似发邮件的功能,当时可以用网易的,现在也不能用了,不知道咋回事,只好作罢。在使用Timer中遇到了之前没有想过的问题--重入。
★介绍
首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件。官方介绍在这里,摘抄如下:
★使用
下面就简单介绍一下,这个Timer是怎么使用的,其实很简单,我就采用微软提供的示例来进行测试,直接上代码了:
★重入问题重现及分析
什么叫重入呢?这是一个有关多线程编程的概念:程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据不一致的情况。Timer方法重入是指使用多线程计时器,一个Timer处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。下面演示一下重入问题的产生(可能重现的不是很好,不过也能简单一下说明问题了):是不是感觉上面输出结果很奇怪,首先是线程1输出为1,没有问题,然后隔了2秒后线程1自增1后输出为2,这就有问题了,中间为什么还出现了线程2的输出?更奇怪的是线程2刚开始输出为1,自增1后尽然变成了3!其实这就是重入所导致的问题。别急,咱们分析一下就知道其中的缘由了。
首先timer启动计时后,开启一个线程1执行方法,当线程1第一次输出之后,这时线程1休眠了2秒,此时timer并没有闲着,因为设置的计时间隔为1秒,当在线程1休眠了1秒后,timer又开启了线程2执行方法,线程2才不管线程1是执行中还是休眠状态,所以此时线程2的输出也为1,因为线程1还在休眠状态,并没有自增。然后又隔了1秒,这时发生同时发生两个事件,线程1过了休眠状态自增输出为2,timer同时又开启一个线程3,线程3输出的为线程1自增后的值2,又过了1秒,线程2过了休眠状态,之前的输出已经是2,所以自增后输出为3,又过了1秒……我都快晕了,大概就是这意思吧,我想表达的就是:一个Timer开启的线程处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。
那怎么解决这个问题呢?解决方案有三种,下面一一道来,适应不同的场景,不过还是推荐最后一种,比较安全。
★重入问题解决方案
1、使用lock(Object)的方法来防止重入,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就等待执行,适用重入很少出现的场景(具体也没研究过,可能比较占内存吧)。代码跟上面差不多,在触发的方法中加入lock,这样当线程2进入触发的方法中,发现已经被锁,会等待锁中的代码处理完在执行,代码如下:
2、设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃(注意这里是放弃,而不是等待哦,看看执行结果就明白啥意思了)执行,适用重入经常出现的场景。代码如下:
3、在多线程下给inTimer赋值不够安全,Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法(感觉比较高上大,也是比较推荐的一种方法),执行结果与方法2一样,也是放弃执行。Interlocked.Exchange用法参考这里。
★总结
终于码完字了,真心不容易啊。写博客是个挺耗精力的事情,真心佩服那些大牛们笔耕不辍,致敬!在这里稍微总结一下,timer是一个使用挺简单的类,拿来即用,这里主要总结了使用timer时重入问题的解决,以前也没思考过这个问题,解决方案也挺简单,在这里列出了三种,主要参考在这里,不知道还有没有其他的方式。这里的解决方案同时也适用多线程的重入问题。
相关文章推荐
- C# TreeView CheckBox 代码挑勾选中
- C#中对字符串的加密和解密
- C#中对字符串的加密和解密
- c#中,DataTable 过滤重复行
- C# 结构
- C# 关于方法中的参数(可选参数和命名参数)
- C# MVC 处理您的请求时发生异常。此外,对第一个异常执行自定义错误页时发生另一异常。已终止请求。
- (转载)C# Process.Kill() 拒绝访问(Access Denied) 的解决方案
- C# GetHashCode 的实现方式
- C#中if和#if区别
- C#中Validating和Validated事件
- C# 之泛型详解
- C#中yield return用法分析
- C# yield关键字详解
- C#操作字符串string
- C# 继承
- C#实现简单的SmtpClient发送邮件
- c#不重复的排序方法
- C# 封装,继承,多态
- c#播放声音文件