C# Thread 点点滴滴

用C#的Thread做了一个简单计时器。为了让自己45分钟后就可以休息一次,45分钟过后会响音乐提示。

开始使用的TimeSpan相减的方式,在Thread的启动函数中也就是这样写的:

  1. public void CountTime()
  2. {
  3.             
  4.    while (true)
  5.    {
  6.       TimeSpan tsNew = new TimeSpan(DateTime.Now.Ticks);
  7.       TimeSpan tsIn = tsNew - tsOld;
  8.       if (tsIn.Minutes >= 1)
  9.       {
  10.     
  11.          while (true)
  12.          {
  13.              TimeSpan tsNewer = new TimeSpan(DateTime.Now.Ticks);
  14.              TimeSpan tsIner = tsNewer - tsNew;
  15.              if (tsIner.Minutes >= 10)
  16.              {
  17.                 //十分钟后线程重启
  18.                  tsOld = tsNew;
  19.                  break;
  20.              }
  21.          }
  22.          
  23.        }
  24.    }
  25. }

后来发现这种方法效率太低了。当然,可以使用Thread.Sleep(20);这个函数降低CPU占用时间。其实中间加入Thread.Sleep(20);就可明显的降低CPU消耗。后来发现C#中的Thread中自带有函数join(),这个函数可以使线程等待一段时间。调用方法如下

th.Join(new TimeSpan(hours, minutes, seconds));在等待的这段时间里线程处于WaitSleepJoin状态。

当然也可以调用Thread.Sleep(millionseconds);这里提一下Sleep和Join的区别

当线程执行Sleep时系统就退出执行队列一段时间,当睡眠结束时,系统会产生一个时钟中断,从而使线程回到执行队列中恢复线程的执行。Sleep方法如果参数是0,代表这个线程应当挂起让其他等待的线程运行,这里cpu回重新分配控制权,也有可能是刚才的执行的程序。这样就会有cpu占用总是100%的情况发生。有时你界面死了,但是你还是可以移动鼠标。如果是Timeout.Infinite,就代表将使线程休眠,直到它被调用 Thread.Interrupt 的另一个线程中断或被 Thread.Abort 中止为止。
    
如果父线程先于子线程结束,那么子线程将在父线程结束的同时被迫结束。Thread.Join()方法使父线程等待,直到子线程结束。Join方法有返回值,当值为true,代表线程终止。false的话代表线程在等待了那段时间后还未终止。如果在线程Unstarted状态时,调用join()就会有ThreadStateException异常。如果线程已经终止,那么调用这个函数,会立即得到返回值。

例如下面的主程序

...

ThreadStart st = New ThreadStart(fun);

Thread th = new Thread(ThreadStart st);

th.Start();

Application.Exit();

...

 

//下面是fun函数

void fun()

{

    while(true)

    {

            ...

    }

}

 

这段程序的唯一毛病就是有可能在主程序退出后,从线程还没有结束。(这个从线程真可怜...)

 

这里顺便再提一下线程的几个状态:

  创建:当创建一个新进程时,也为该进程创建了一个线程。线程还可以创建新线程。

  就绪:线程已获得除处理机外的所有资源。

  运行:线程正在处理机上执行。

  阻塞:线程因等待某事件而暂停运行。

  终止:一个线程已完成。

 

但是C#的线程中多了几个状态:

Aborted,AbortRequested,Background,Running,Stopped,StopRequested,Suspended,SuspendRequested,Unstarted,WaitSleepJoin。

  Abort()将导致ThreadState.AbortRequested调用Abort()的线程获得控制权之后导致ThreadState.Aborted,AbortRequested与Aborted的区别在于一个停止一个未停止。而Stopped则是线程终止。但是我反复试验多次发现当调用Abort()函数后,线程状态会变为Stopped。如何变为Aborted状态,还在研究中。其他几个状态差不多。都是调用相应的函数会产生相应的状态请求,还有过一段时间才能到底相应的状态。至于Unstarted是还未调用Start()函数,Running是调用Start()或者Resume()函数的结果。WaitSleepJoin是在等待I/O,或者是调用Join()方法。这里Join()和Sleep()方法的不同还在于调用Join()线程状态进入WaitSleepJoin,调用Sleep()线程状态还是Running。

 

挂起线程的方法是Suspend();调用这个方法后,线程处于SuspendRequest状态。Suspended()调用后如果线程仍然在执行join()方法,因为Suspended()要让线程到达安全点之后它才可以将该线程挂起,此时那线程状态就是SuspendRequested|WaitSleepJoin。但是这里的join里的时钟依然在计数。所以现在还不知道用什么方法来暂停这个join计数,当然也可以不使用join解决彻底暂停线程这个问题。现在不明白哪个Suspended()函数是干什么的,因为线程依旧在运行中。另外值得一提的是现在不提倡使用Suspend()和让线程调用Suspend()后再次恢复的Resume()方法。原因很简单,因为这两个方法是由另外的线程执行,另外的线程并不能准确的知道被Suspend()的线程处于何种状态,如某个类的构造函数执行时期,或者析构等。所以用这个函数来同步很危险。

 

另外,要注意的是Thread.Sleep(n)这个n不能精确的控制时间。如果你认为要线程要隔多长时间,这个控制就有问题。如果当前的线程是一个前台线程,那么Thread.Sleep(n)就要在大于n的时间才能退出。如果是后台进程,当主程序退出后,这线程就再也不能唤醒..悲惨..所以一般也建议不用Thread.Sleep()函数。另外Sleep函数也不能用于同步.peter说程序的Sleep函数代表了一个很烂的设计。

 

做了个计时器竟然引发了这些问题...疯...

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值