你的位置:首页 > ASP.net教程

[ASP.net教程]C#多线程实践——线程同步


  下面的表格列展了.NET对协调或同步线程动作的可用的工具:

                      简易阻止方法

构成

目的

Sleep

阻止给定的时间周期

Join

等待另一个线程完成

                      锁系统

构成

目的

跨进程?

速度

lock

确保只有一个线程访问某个资源或某段代码。

Mutex

确保只有一个线程访问某个资源或某段代码。可被用于防止一个程序的多个实例同时运行。

中等

Semaphore

确保不超过指定数目的线程访问某个资源或某段代码。

中等

 

                    信号系统

构成

目的

跨进程?

速度

EventWaitHandle

允许线程等待直到它受到了另一个线程发出信号。

中等

Wait 和 Pulse*

允许一个线程等待直到自定义阻止条件得到满足。

中等

 

同步要领

阻止(Blocking)

  当一个线程通过上面所列的方式处于等待或暂停的状态,被称为被阻止。一旦被阻止,线程立刻放弃它被分配的CPU时间,将它的ThreadState属性添加为WaitSleepJoin状态,直到停止阻止。停止阻止由以下任一条件触发:

  • 阻止的条件已得到满足
  • 操作超时(如果timeout被指定了)
  • 通过Thread.Interrupt中断了
  • 通过Thread.Abort放弃了

   当线程通过(不建议)Suspend 方法暂停,不认为是被阻止了。

休眠 和 轮询

  调用Thread.Sleep阻止当前的线程指定的时间(或者直到中断):

static void Main() {  Thread.Sleep (0);              // 释放CPU时间片  Thread.Sleep (1000);            // 休眠1000毫秒  Thread.Sleep (TimeSpan.FromHours (1));   // 休眠1小时  Thread.Sleep (Timeout.Infinite);      // 休眠直到中断}

  确切地说,Thread.Sleep放弃了占用CPU,请求不再被分配时间直到超过某个给定的时间。Thread.Sleep(0)放弃

CPU的时间刚刚够其它在时间片队列里的活动线程(如果有的话)被执行。

     Thread.Sleep在阻止方法中是唯一的暂停汲取Windows Forms程序的Windows消息的方法,或COM环境中用于

单元模式。这在Windows Forms程序中是一个很大的问题,任何对主UI线程的阻止都将使程序失去相应。因此一般避

免这样使用,无论信息汲取是否被“技术地”暂定与否。由COM遗留下来的宿主环境更为复杂,在一些时候它决定停止,

而却保持信息的汲取存活。微软的 Chris Brumm 在他的博客中讨论这个问题。(搜索: 'COM "Chris Brumme"')

    线程类同时也提供了一个SpinWait方法,它使用轮询CPU而非放弃CPU时间的方式,保持给定的迭代次数进行“无用

地繁忙”。50迭代可能等同于停顿大约一微秒,虽然这将取决于CPU的速度和负载。从技术上讲,SpinWait并不是一个阻

止的方法:一个处于spin-waiting的线程的ThreadState不是WaitSleepJoin状态,并且也不会被其它的线程过早的中断

(Interrupt)。SpinWait很少被使用,它的作用是等待一个在极短时间(可能小于一微秒)内可准备好的可预期的资源,

而不用调用Sleep方法阻止线程而浪费CPU时间。不过,这种技术的优势只有在多处理器计算机:对单一处理器的电脑,

直到轮询的线程结束了它的时间片之前,一个资源没有机会改变状态,这有违它的初衷。并且调用SpinWait经常会花费较

长的时间这本身就浪费了CPU时间。

 阻止 vs. 轮询

    线程可以等待某个确定的条件来明确轮询使用一个轮询的方式,比如:

while (!proceed);

    或者:

while (DateTime.Now < nextStartTime);

  这是非常浪费CPU时间的:对于CLR和操作系统而言,线程进行了一个重要的计算,所以分配了相应的资源!在这种状态

下的轮询线程不算是阻止,不像一个线程等待一个EventWaitHandle(一般使用这样的信号任务来构建)。

     阻止和轮询组合使用可以产生一些变换:

while (!proceed) Thread.Sleep (x); // "轮询休眠!"

  x越大,CPU效率越高,折中方案是增大潜伏时间,任何20ms的花费是微不足道的,除非循环中的条件是极其复杂的。

    除了稍有延迟,这种轮询和休眠的方式可以结合的非常好。(但有并发问题,在第四部分讨论)可能它最大的用处在于

程序员可以放弃使用复杂的信号结构 来工作了。