SemaphoreSlim 类

定义

对可同时访问资源或资源池的线程数加以限制的 Semaphore 的轻量替代。

public ref class SemaphoreSlim : IDisposable
public class SemaphoreSlim : IDisposable
[System.Runtime.InteropServices.ComVisible(false)]
public class SemaphoreSlim : IDisposable
type SemaphoreSlim = class
    interface IDisposable
[<System.Runtime.InteropServices.ComVisible(false)>]
type SemaphoreSlim = class
    interface IDisposable
Public Class SemaphoreSlim
Implements IDisposable
继承
SemaphoreSlim
属性
实现

示例

以下示例创建一个信号灯,最大计数为三个线程,初始计数为零个线程。 该示例启动五个任务,所有这些任务都阻止等待信号灯。 主线程调用 Release(Int32) 重载以将信号灯计数增加到其最大值,这允许三个任务进入信号灯。 每次释放信号灯时,都会显示以前的信号灯计数。 控制台消息跟踪信号灯的使用。 每个线程的模拟工作间隔略有增加,以使输出更易于读取。

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
    private static SemaphoreSlim semaphore;
    // A padding interval to make the output more orderly.
    private static int padding;

    public static void Main()
    {
        // Create the semaphore.
        semaphore = new SemaphoreSlim(0, 3);
        Console.WriteLine("{0} tasks can enter the semaphore.",
                          semaphore.CurrentCount);
        Task[] tasks = new Task[5];

        // Create and start five numbered tasks.
        for (int i = 0; i <= 4; i++)
        {
            tasks[i] = Task.Run(() =>
            {
                // Each task begins by requesting the semaphore.
                Console.WriteLine("Task {0} begins and waits for the semaphore.",
                                  Task.CurrentId);
                
                int semaphoreCount;
                semaphore.Wait();
                try
                {
                    Interlocked.Add(ref padding, 100);

                    Console.WriteLine("Task {0} enters the semaphore.", Task.CurrentId);

                    // The task just sleeps for 1+ seconds.
                    Thread.Sleep(1000 + padding);
                }
                finally {
                    semaphoreCount = semaphore.Release();
                }
                Console.WriteLine("Task {0} releases the semaphore; previous count: {1}.",
                                  Task.CurrentId, semaphoreCount);
            });
        }

        // Wait for half a second, to allow all the tasks to start and block.
        Thread.Sleep(500);

        // Restore the semaphore count to its maximum value.
        Console.Write("Main thread calls Release(3) --> ");
        semaphore.Release(3);
        Console.WriteLine("{0} tasks can enter the semaphore.",
                          semaphore.CurrentCount);
        // Main thread waits for the tasks to complete.
        Task.WaitAll(tasks);

        Console.WriteLine("Main thread exits.");
    }
}
// The example displays output like the following:
//       0 tasks can enter the semaphore.
//       Task 1 begins and waits for the semaphore.
//       Task 5 begins and waits for the semaphore.
//       Task 2 begins and waits for the semaphore.
//       Task 4 begins and waits for the semaphore.
//       Task 3 begins and waits for the semaphore.
//       Main thread calls Release(3) --> 3 tasks can enter the semaphore.
//       Task 4 enters the semaphore.
//       Task 1 enters the semaphore.
//       Task 3 enters the semaphore.
//       Task 4 releases the semaphore; previous count: 0.
//       Task 2 enters the semaphore.
//       Task 1 releases the semaphore; previous count: 0.
//       Task 3 releases the semaphore; previous count: 0.
//       Task 5 enters the semaphore.
//       Task 2 releases the semaphore; previous count: 1.
//       Task 5 releases the semaphore; previous count: 2.
//       Main thread exits.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Private semaphore As SemaphoreSlim
    ' A padding interval to make the output more orderly.
    Private padding As Integer

   Public Sub Main()
      ' Create the semaphore.
      semaphore = New SemaphoreSlim(0, 3)
      Console.WriteLine("{0} tasks can enter the semaphore.",
                        semaphore.CurrentCount)
      Dim tasks(4) As Task

      ' Create and start five numbered tasks.
      For i As Integer = 0 To 4
         tasks(i) = Task.Run(
            Sub()
               ' Each task begins by requesting the semaphore.
               Console.WriteLine("Task {0} begins and waits for the semaphore.",
                              Task.CurrentId)
               semaphore.Wait()

               Interlocked.Add(padding, 100)

               Console.WriteLine("Task {0} enters the semaphore.", Task.CurrentId)

               ' The task just sleeps for 1+ seconds.
               Thread.Sleep(1000 + padding)

               Console.WriteLine("Task {0} releases the semaphore previous count: {1}.",
                                 Task.CurrentId, semaphore.Release())
            End Sub )
      Next

      ' Wait for half a second, to allow all the tasks to start and block.
      Thread.Sleep(500)

      ' Restore the semaphore count to its maximum value.
      Console.Write("Main thread calls Release(3) --> ")
      semaphore.Release(3)
      Console.WriteLine("{0} tasks can enter the semaphore.",
                        semaphore.CurrentCount)
      ' Main thread waits for the tasks to complete.
      Task.WaitAll(tasks)

      Console.WriteLine("Main thread exits.")
   End Sub
End Module
' The example displays output like the following:
'       0 tasks can enter the semaphore.
'       Task 1 begins and waits for the semaphore.
'       Task 5 begins and waits for the semaphore.
'       Task 2 begins and waits for the semaphore.
'       Task 4 begins and waits for the semaphore.
'       Task 3 begins and waits for the semaphore.
'       Main thread calls Release(3) --> 3 tasks can enter the semaphore.
'       Task 4 enters the semaphore.
'       Task 1 enters the semaphore.
'       Task 3 enters the semaphore.
'       Task 4 releases the semaphore; previous count: 0.
'       Task 2 enters the semaphore.
'       Task 1 releases the semaphore; previous count: 0.
'       Task 3 releases the semaphore; previous count: 0.
'       Task 5 enters the semaphore.
'       Task 2 releases the semaphore; previous count: 1.
'       Task 5 releases the semaphore; previous count: 2.
'       Main thread exits.

注解

信号灯有两种类型:本地信号灯和命名系统信号灯。 本地信号灯是应用程序的本地信号量,系统信号量在整个操作系统中可见,适合进程间同步。 这是SemaphoreSlim不使用内核信号量Windows类的轻型替代Semaphore方法。 与类 Semaphore 不同,该 SemaphoreSlim 类不支持命名的系统信号灯。 只能将其用作本地信号灯。 类 SemaphoreSlim 是建议在单个应用中同步的信号灯。

轻型信号灯控制对应用程序本地资源的池的访问。 实例化信号灯时,可以指定可以同时输入信号灯的最大线程数。 还可以指定可以同时输入信号量的初始线程数。 这定义了信号灯的计数。

每次线程进入信号灯时,计数都会递减,每次线程释放信号灯时递增。 若要输入信号灯,线程会调用其中一个 WaitWaitAsync 重载。 若要释放信号灯,它会调用其中一个 Release 重载。 当计数达到零时,对其中一 Wait 个方法的后续调用会阻止,直到其他线程释放信号灯。 如果阻止了多个线程,则无法保证顺序(例如 FIFO 或 LIFO),用于控制线程何时进入信号灯。

使用信号灯保护资源的代码的基本结构是:

' Enter semaphore by calling one of the Wait or WaitAsync methods.
SemaphoreSlim.Wait()
'
' Execute code protected by the semaphore.
'
SemaphoreSlim.Release()

当所有线程都释放信号灯时,计数处于创建信号灯时指定的最大值。 信号灯的计数可从 CurrentCount 属性获取。

重要

SemaphoreSlim不会对调用WaitWaitAsyncRelease和方法强制实施线程或任务标识。 此外,如果 SemaphoreSlim(Int32) 构造函数用于实例化 SemaphoreSlim 对象,则 CurrentCount 属性可以超出构造函数设置的值。 程序员有责任确保对 Wait 方法的调用或 WaitAsync 方法的调用与调用 Release 正确配对。

构造函数

SemaphoreSlim(Int32)

初始化 SemaphoreSlim 类的新实例,以指定可同时授予的请求的初始数量。

SemaphoreSlim(Int32, Int32)

初始化 SemaphoreSlim 类的新实例,同时指定可同时授予的请求的初始数量和最大数量。

属性

AvailableWaitHandle

返回一个可用于在信号量上等待的 WaitHandle

CurrentCount

获取可以输入 SemaphoreSlim 对象的剩余线程数。

方法

Dispose()

释放 SemaphoreSlim 类的当前实例所使用的所有资源。

Dispose(Boolean)

释放由 SemaphoreSlim 占用的非托管资源,还可以另外再释放托管资源。

Equals(Object)

确定指定对象是否等于当前对象。

(继承自 Object)
GetHashCode()

作为默认哈希函数。

(继承自 Object)
GetType()

获取当前实例的 Type

(继承自 Object)
MemberwiseClone()

创建当前 Object 的浅表副本。

(继承自 Object)
Release()

释放 SemaphoreSlim 对象一次。

Release(Int32)

释放 SemaphoreSlim 对象指定的次数。

ToString()

返回表示当前对象的字符串。

(继承自 Object)
Wait()

阻止当前线程,直至它可进入 SemaphoreSlim 为止。

Wait(CancellationToken)

阻止当前线程,直至它可进入 SemaphoreSlim 为止,同时观察 CancellationToken

Wait(Int32)

阻止当前线程,直至它可进入 SemaphoreSlim 为止,同时使用 32 位带符号整数来指定超时。

Wait(Int32, CancellationToken)

阻止当前线程,直至它可进入 SemaphoreSlim 为止,并使用 32 位带符号整数来指定超时,同时观察 CancellationToken

Wait(TimeSpan)

阻止当前线程,直至它可进入 SemaphoreSlim 为止,同时使用 TimeSpan 来指定超时。

Wait(TimeSpan, CancellationToken)

阻止当前线程,直至它可进入 SemaphoreSlim 为止,并使用 TimeSpan 来指定超时,同时观察 CancellationToken

WaitAsync()

输入 SemaphoreSlim 的异步等待。

WaitAsync(CancellationToken)

在观察 CancellationToken 时,输入 SemaphoreSlim 的异步等待。

WaitAsync(Int32)

输入 SemaphoreSlim 的异步等待,使用 32 位带符号整数度量时间间隔。

WaitAsync(Int32, CancellationToken)

在观察 CancellationToken 时,输入 SemaphoreSlim 的异步等待,使用 32 位带符号整数度量时间间隔。

WaitAsync(TimeSpan)

输入 SemaphoreSlim 的异步等待,使用 TimeSpan 度量时间间隔。

WaitAsync(TimeSpan, CancellationToken)

在观察 SemaphoreSlim 时,输入 TimeSpan 的异步等待,使用 CancellationToken 度量时间间隔。

适用于

线程安全性

所有公共成员和受保护的成员 SemaphoreSlim 都是线程安全的,并且可能同时从多个线程使用,但例外,只有在 Dispose()已完成所有其他操作 SemaphoreSlim 时才使用。

另请参阅