详细介绍C#Thread点点滴滴


本文摘自PHP中文网,作者黄舟,侵删。

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

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

  1. 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

    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异常。如果线程已经终止,那么调用这个函数,会立即得到返回值。

例如下面的主程序

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

...

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点点滴滴的详细内容!

相关阅读 >>

C#高级编程(一)-.net体系结构

C#中关于new的用法以及和override的区别分析详解

C#设计模式-派生类实现非虚接口陷阱的实例代码分享

详解C# 控制台倒计时

C#中正则表达式有什么作用?匹配字符有什么含义?

C#开发实例-订制屏幕截图工具(九)使用自定义光标和qq截图时的光标(图)

详解C#生成随机数功能的代码示例

C#构建分页应用的实例方法分析

具体详解C#中三个关键字(params,ref,out)

详解C#使用litjson解析json的示例代码

更多相关阅读请进入《C#》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...