Semaphore 和 SemaphoreSlim

System.Threading.Semaphore 类表示一个命名(系统范围)信号量或本地信号量。 它是一个对 Win32 信号量对象的精简包装。 Win32 信号量是计数信号量,可用于控制对资源池的访问。

SemaphoreSlim 类表示一个轻量的快速信号量,可用于在一个预计等待时间会非常短的进程内进行等待。 SemaphoreSlim 会尽可能多地依赖由公共语言运行时 (CLR) 提供的同步基元。 但是,它也会根据需要提供延迟初始化的、基于内核的等待句柄,以支持等待多个信号量。 SemaphoreSlim 还支持使用取消标记,但它不支持命名信号量或使用等待句柄来进行同步。

管理受限资源

线程通过调用 WaitOne 方法来进入信号量,此方法是从 WaitHandle 类派生的。 当调用返回时,信号量的计数将减少。 当一个线程请求项而计数为零时,该线程会被阻止。 当线程通过调用 Semaphore.Release 方法释放信号量时,将允许被阻止的线程进入。 并不保证被阻塞的线程进入信号量的顺序,例如先进先出 (FIFO) 或后进先出 (LIFO)。

线程可以通过重复调用 WaitOne 方法来多次进入信号量。 若要释放信号量,线程可以调用 Release() 方法重载相同的次数,也可以调用 Release(Int32) 方法重载并指定要释放的项数。

信号量和线程标识

Semaphore 类不对向 WaitOneRelease 方法发出的调用强制线程标识。 例如,信号量的一个常用方案包括一个生产者线程和一个使用者线程,其中一个线程总是增加信号量计数,而另一个线程总是减少信号量计数。

编程人员应负责确保线程释放信号量的次数不会过多。 例如,假定信号量的最大计数为二,线程 A 和线程 B 都进入信号量。 如果线程 B 中的编程错误导致它两次调用 Release,则两次调用都成功。 这样,信号量的计数就已经达到了最大值,所以,当线程 A 最终调用 Release 时,将引发 SemaphoreFullException

命名信号量

Windows 操作系统允许信号量具有名称。 命名信号量在整个系统级都有效。 即,创建命名信号量后,所有进程中的所有线程都是可见的。 因此,命名信号量可用于同步进程的活动以及线程的活动。

您可以使用可用于指定名称的一个构造函数来创建表示命名系统信号量的 Semaphore 对象。

注意注意

因为命名信号量是针对整个系统级的,所以可以具有多个表示同一命名信号量的 Semaphore 对象。每当调用构造函数或 Semaphore.OpenExisting 方法时,都会创建一个新的 Semaphore 对象。重复指定相同的名称将创建多个表示同一命名信号量的对象。

使用命名信号量时一定要小心。 因为命名信号量是针对整个系统级的,所以使用同一名称的其他进程可能会意外地进入您的信号量。 在同一计算机上执行的恶意代码可能以此作为一个切入点来发动拒绝服务攻击。

使用访问控制安全机制来保护表示命名信号量的 Semaphore 对象,最好通过使用可用于指定 System.Security.AccessControl.SemaphoreSecurity 对象的构造函数来实施保护。 您还可以使用 Semaphore.SetAccessControl 方法来应用访问控制安全,但这一做法会在信号量创建时间和信号量受保护时间之间留出一段漏洞时间。 使用访问控制安全机制保护信号量可帮助阻止恶意攻击,但无法解决意外发生的名称冲突问题。

请参见

参考

Semaphore

SemaphoreSlim

其他资源

线程处理对象和功能