首页 >后端开发 >C#.Net教程 >详细介绍C#Thread点点滴滴

详细介绍C#Thread点点滴滴

黄舟
黄舟原创
2017-03-20 13:17:171876浏览

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

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

  1. public void CountTime()
    {
                
       while (true)
       {
          TimeSpan tsNew = new TimeSpan(DateTime.Now.Ticks);
          TimeSpan tsIn = tsNew - tsOld;
          if (tsIn.Minutes >= 1)
          {
        
             while (true)
             {
                 TimeSpan tsNewer = new TimeSpan(DateTime.Now.Ticks);
                 TimeSpan tsIner = tsNewer - tsNew;
                 if (tsIner.Minutes >= 10)
                 {
                    //十分钟后线程重启
                     tsOld = tsNew;
                     break;
                 }
             }
             
           }
       }
    }

后来发现这种方法效率太低了。当然,可以使用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函数代表了一个很烂的设计。

 

以上是详细介绍C#Thread点点滴滴的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn