通过


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, Int32)

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

SemaphoreSlim(Int32)

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

属性

名称 说明
AvailableWaitHandle

返回可用于等待信号灯的 a 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,同时观察 a CancellationToken.

Wait(Int32, CancellationToken)

阻止当前线程,直到它可以使用指定超时的 32 位有符号整数来输入 SemaphoreSlim该线程,同时观察超时 CancellationToken

Wait(Int32)

阻止当前线程,直到它可以使用指定超时的 32 位有符号整数进入 SemaphoreSlim该线程。

Wait(TimeSpan, CancellationToken)

阻止当前线程,直到它可以使用SemaphoreSlimTimeSpan指定超时值,同时观察超时CancellationToken

Wait(TimeSpan)

阻止当前线程,直到它可以输入 SemaphoreSlim,使用 a TimeSpan 指定超时。

WaitAsync()

异步等待输入 SemaphoreSlim

WaitAsync(CancellationToken)

异步等待输入 SemaphoreSlim,同时观察 a CancellationToken.

WaitAsync(Int32, CancellationToken)

异步等待输入 SemaphoreSlim,使用 32 位带符号整数测量时间间隔,同时观察一个 CancellationToken

WaitAsync(Int32)

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

WaitAsync(TimeSpan, CancellationToken)

异步等待输入 SemaphoreSlim,使用 a TimeSpan 测量时间间隔,同时观察一个 CancellationToken

WaitAsync(TimeSpan)

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

适用于

线程安全性

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

另请参阅