timer类线程的使用时根据时间间隔,不停启动线程。他不会因为上一个线程没有运行完而不启动线程。也就是timer的定时启动线程没有任何条件限制,无论什么情况都会启动线程。
很多情况下定时启动的线程其实是希望顺序执行的,也就上一个线程没有执行完的是很下面的线程是不希望执行的。或者并不是很讲究顺序,而是只希望同一个时刻只有一个线程在运行,这个线程在运行的时候其他后启动的线程是直接不启动,或者启动了不真正执行操作。
在这个需求的背景下,产生了这个线程同步的问题。我使用之值类型的方式同步。是用一个bool类型的状态变量判断是否当前是否有线程在使用。如果有当前线程直接将线程return。在线程启动后且判断状态位为可用后,设置状态位,在线程的最后将状态变量复位。
这样的思路是正确的,而且其思路其实就是信号机制,不过信号机制在等待信号的时候是将当前线程阻断等到信号后再执行,我这边是信号表示繁忙时,立刻将当前线程return掉。
但是细细想来有几个不严谨的地方。
第一点:例如,一个线程第一句话获得判断状态位后第二句话才是设置状态位为繁忙,如果正不巧,在执行第二句话之前,另外一个线程也启动了,恰巧也执行了执行了第一句话也就通过了状态判断,程序就会出现2个线程同时执行而产生线程同步问题。其实这个问题很少会发生因为timer类线程是顺序启动的,启动间隔足够执行一个值类型的操作。但是,这个情况往往会在线程调试特别中断在判断设置状态位为繁忙这一句上。想想是不是呢。
第二点:正常情况下,线程的具体操作我们都会用try执行进行容错,为了防止中间意外的退出,我们会在finally里加上重置的语句。这里需要切忌一点,线程开头判断状态位进行return操作的语句不能放在try中,要么会因为finally里的语句而造成状态位失效了。
第二点很好解决,只要放在线程的开头,因为值类型的操作也不会产生什么错误。
第一点的解决就要稍微繁琐一点。其实原理也很简单,用lock这类同步方式,在进行判断与设置两步操作上lock一下,或者用其他信号机制已保证判断与设置状态时只能有一个线程在操作。比较郁闷的是值类型是不能被lock的(因为值类型的操作是不会产生同步问题的)所以还得设置一个objec用来lock变量,呵呵。
其实还有一个小问题,比如线程如果里面有什么报错,或者其他什么在调试时候人为原因而造成finally里的重置状态位未执行,可以在监控窗口里监控状态位变量,在发生这个问题的时候手动在监控窗口里复位一下值。
下面列出代码的模板
1: private bool isRunning;
2: private object syncRot=new object();
3: private void timerThreadFunction(object status)
4: {
5: lock(this.syncRot)
6: {
7: //判断状态位及设置状态位操作
8: if(this.sRunning) return;
9: this.isRunning=true;
10: }
11: try
12: {
13: //线程具体操作
14: }
15: catch
16: {
17: //容错操作
18: }
19: finally
20: {
21: //复位操作
22: this.isRunning=false;
23: }
24: }