Semaphore 类

定义

限制可同时访问某一资源或资源池的线程数。

public ref class Semaphore sealed : System::Threading::WaitHandle
public sealed class Semaphore : System.Threading.WaitHandle
[System.Runtime.InteropServices.ComVisible(false)]
public sealed class Semaphore : System.Threading.WaitHandle
type Semaphore = class
    inherit WaitHandle
[<System.Runtime.InteropServices.ComVisible(false)>]
type Semaphore = class
    inherit WaitHandle
Public NotInheritable Class Semaphore
Inherits WaitHandle
继承
Semaphore
继承
属性

示例

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

#using <System.dll>
using namespace System;
using namespace System::Threading;

public ref class Example
{
private:
   // A semaphore that simulates a limited resource pool.
   //
   static Semaphore^ _pool;

   // A padding interval to make the output more orderly.
   static int _padding;

public:
   static void Main()
   {
      // Create a semaphore that can satisfy up to three
      // concurrent requests. Use an initial count of zero,
      // so that the entire semaphore count is initially
      // owned by the main program thread.
      //
      _pool = gcnew Semaphore( 0,3 );
      
      // Create and start five numbered threads.
      //
      for ( int i = 1; i <= 5; i++ )
      {
         Thread^ t = gcnew Thread(
            gcnew ParameterizedThreadStart( Worker ) );
         
         // Start the thread, passing the number.
         //
         t->Start( i );
      }
      
      // Wait for half a second, to allow all the
      // threads to start and to block on the semaphore.
      //
      Thread::Sleep( 500 );
      
      // The main thread starts out holding the entire
      // semaphore count. Calling Release(3) brings the
      // semaphore count back to its maximum value, and
      // allows the waiting threads to enter the semaphore,
      // up to three at a time.
      //
      Console::WriteLine( L"Main thread calls Release(3)." );
      _pool->Release( 3 );

      Console::WriteLine( L"Main thread exits." );
   }

private:
   static void Worker( Object^ num )
   {
      // Each worker thread begins by requesting the
      // semaphore.
      Console::WriteLine( L"Thread {0} begins and waits for the semaphore.", num );
      _pool->WaitOne();
      
      // A padding interval to make the output more orderly.
      int padding = Interlocked::Add( _padding, 100 );

      Console::WriteLine( L"Thread {0} enters the semaphore.", num );
      
      // The thread's "work" consists of sleeping for
      // about a second. Each thread "works" a little
      // longer, just to make the output more orderly.
      //
      Thread::Sleep( 1000 + padding );

      Console::WriteLine( L"Thread {0} releases the semaphore.", num );
      Console::WriteLine( L"Thread {0} previous semaphore count: {1}",
         num, _pool->Release() );
   }
};
using System;
using System.Threading;

public class Example
{
    // A semaphore that simulates a limited resource pool.
    //
    private static Semaphore _pool;

    // A padding interval to make the output more orderly.
    private static int _padding;

    public static void Main()
    {
        // Create a semaphore that can satisfy up to three
        // concurrent requests. Use an initial count of zero,
        // so that the entire semaphore count is initially
        // owned by the main program thread.
        //
        _pool = new Semaphore(initialCount: 0, maximumCount: 3);

        // Create and start five numbered threads. 
        //
        for(int i = 1; i <= 5; i++)
        {
            Thread t = new Thread(new ParameterizedThreadStart(Worker));

            // Start the thread, passing the number.
            //
            t.Start(i);
        }

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

        // The main thread starts out holding the entire
        // semaphore count. Calling Release(3) brings the 
        // semaphore count back to its maximum value, and
        // allows the waiting threads to enter the semaphore,
        // up to three at a time.
        //
        Console.WriteLine("Main thread calls Release(3).");
        _pool.Release(releaseCount: 3);

        Console.WriteLine("Main thread exits.");
    }

    private static void Worker(object num)
    {
        // Each worker thread begins by requesting the
        // semaphore.
        Console.WriteLine("Thread {0} begins " +
            "and waits for the semaphore.", num);
        _pool.WaitOne();

        // A padding interval to make the output more orderly.
        int padding = Interlocked.Add(ref _padding, 100);

        Console.WriteLine("Thread {0} enters the semaphore.", num);
        
        // The thread's "work" consists of sleeping for 
        // about a second. Each thread "works" a little 
        // longer, just to make the output more orderly.
        //
        Thread.Sleep(1000 + padding);

        Console.WriteLine("Thread {0} releases the semaphore.", num);
        Console.WriteLine("Thread {0} previous semaphore count: {1}",
            num, _pool.Release());
    }
}
Imports System.Threading

Public Class Example

    ' A semaphore that simulates a limited resource pool.
    '
    Private Shared _pool As Semaphore

    ' A padding interval to make the output more orderly.
    Private Shared _padding As Integer

    <MTAThread> _
    Public Shared Sub Main()
        ' Create a semaphore that can satisfy up to three
        ' concurrent requests. Use an initial count of zero,
        ' so that the entire semaphore count is initially
        ' owned by the main program thread.
        '
        _pool = New Semaphore(0, 3)

        ' Create and start five numbered threads. 
        '
        For i As Integer = 1 To 5
            Dim t As New Thread(New ParameterizedThreadStart(AddressOf Worker))
            'Dim t As New Thread(AddressOf Worker)

            ' Start the thread, passing the number.
            '
            t.Start(i)
        Next i

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

        ' The main thread starts out holding the entire
        ' semaphore count. Calling Release(3) brings the 
        ' semaphore count back to its maximum value, and
        ' allows the waiting threads to enter the semaphore,
        ' up to three at a time.
        '
        Console.WriteLine("Main thread calls Release(3).")
        _pool.Release(3)

        Console.WriteLine("Main thread exits.")
    End Sub

    Private Shared Sub Worker(ByVal num As Object)
        ' Each worker thread begins by requesting the
        ' semaphore.
        Console.WriteLine("Thread {0} begins " _
            & "and waits for the semaphore.", num)
        _pool.WaitOne()

        ' A padding interval to make the output more orderly.
        Dim padding As Integer = Interlocked.Add(_padding, 100)

        Console.WriteLine("Thread {0} enters the semaphore.", num)
        
        ' The thread's "work" consists of sleeping for 
        ' about a second. Each thread "works" a little 
        ' longer, just to make the output more orderly.
        '
        Thread.Sleep(1000 + padding)

        Console.WriteLine("Thread {0} releases the semaphore.", num)
        Console.WriteLine("Thread {0} previous semaphore count: {1}", _
            num, _
            _pool.Release())
    End Sub
End Class

注解

Semaphore使用 类控制对资源池的访问。 线程通过调用 WaitOne 继承自 WaitHandle 类的 方法进入信号灯,并通过调用 Release 方法释放信号量。

每次线程进入信号灯时,信号灯上的计数都会递减,并在线程释放信号量时递增。 当计数为零时,后续请求会阻塞,直到其他线程释放信号灯。 当所有线程都释放信号灯时,计数为创建信号量时指定的最大值。

没有保证的顺序,例如 FIFO 或 LIFO,阻止的线程进入信号量。

线程可以通过重复调用 WaitOne 方法多次进入信号灯。 若要释放部分或全部这些条目,线程可以多次调用无 Release() 参数方法重载,也可以调用 Release(Int32) 指定要释放的条目数的方法重载。

Semaphore 不会在调用 WaitOneRelease时强制实施线程标识。 程序员有责任确保线程不会释放信号灯太多次。 例如,假定信号量的最大计数为 2 并且线程 A 和线程 B 都进入了该信号量。 如果线程 B 中的编程错误导致它两次成功调用了 Release。 信号灯计数已满,当线程 A 最终调用 Release 时,SemaphoreFullException 抛出。

信号灯有两种类型:本地信号灯和命名系统信号灯。 如果使用接受名称的构造函数创建 Semaphore 对象,则它与该名称的操作系统信号量相关联。 命名系统信号灯在整个操作系统中可见,可用于同步进程的活动。 可以创建多个 Semaphore 表示同一命名系统信号量的对象,并且可以使用 OpenExisting 方法打开现有的命名系统信号量。

本地信号灯仅存在于进程内。 进程中引用本地 Semaphore 对象的所有线程都可以使用本地 mutex。 每个对象都是 Semaphore 一个单独的本地信号灯。

注意

默认情况下,命名信号量不仅限于创建它的用户。 其他用户可能能够打开和使用信号灯,包括通过多次获取信号灯而不释放信号灯来干扰信号量。 若要限制对特定用户的访问,可以在创建命名信号量时使用构造函数重载或 SemaphoreAcl 并传入 SemaphoreSecurity 。 避免在没有访问限制的情况下使用命名信号灯,这些信号灯对可能具有不受信任的用户运行代码的系统。

构造函数

Semaphore(Int32, Int32)

初始化 Semaphore 类的新实例,并指定初始入口数和最大并发入口数。

Semaphore(Int32, Int32, String)

初始化 Semaphore 类的新实例,并指定初始入口数和最大并发入口数,可以选择指定系统信号量对象的名称。

Semaphore(Int32, Int32, String, Boolean)

初始化 Semaphore 类的新实例,并指定初始入口数和最大并发入口数,还可以选择指定系统信号量对象的名称,以及指定一个变量来接收指示是否创建了新系统信号量的值。

Semaphore(Int32, Int32, String, Boolean, SemaphoreSecurity)

初始化 Semaphore 类的新实例,并指定初始入口数和最大并发入口数,可以选择指定系统信号量对象的名称,指定一个变量来接收指示是否创建了新系统信号量的值,以及指定系统信号量的安全访问控制。

字段

WaitTimeout

指示在任何等待句柄终止之前 WaitAny(WaitHandle[], Int32, Boolean) 操作已超时。 此字段为常数。

(继承自 WaitHandle)

属性

Handle
已过时.
已过时.

获取或设置本机操作系统句柄。

(继承自 WaitHandle)
SafeWaitHandle

获取或设置本机操作系统句柄。

(继承自 WaitHandle)

方法

Close()

释放由当前 WaitHandle 占用的所有资源。

(继承自 WaitHandle)
CreateObjRef(Type)

创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息。

(继承自 MarshalByRefObject)
Dispose()

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

(继承自 WaitHandle)
Dispose(Boolean)

当在派生类中重写时,释放 WaitHandle 使用的非托管资源,并且可选择释放托管资源。

(继承自 WaitHandle)
Equals(Object)

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

(继承自 Object)
GetAccessControl()

获取已命名的系统信号量的访问控制安全性。

GetHashCode()

作为默认哈希函数。

(继承自 Object)
GetLifetimeService()
已过时.

检索控制此实例的生存期策略的当前生存期服务对象。

(继承自 MarshalByRefObject)
GetType()

获取当前实例的 Type

(继承自 Object)
InitializeLifetimeService()
已过时.

获取生存期服务对象来控制此实例的生存期策略。

(继承自 MarshalByRefObject)
MemberwiseClone()

创建当前 Object 的浅表副本。

(继承自 Object)
MemberwiseClone(Boolean)

创建当前 MarshalByRefObject 对象的浅表副本。

(继承自 MarshalByRefObject)
OpenExisting(String)

打开指定名称为信号量(如果已经存在)。

OpenExisting(String, SemaphoreRights)

用安全访问权限打开指定名称为信号量(如果已经存在)。

Release()

退出信号量并返回前一个计数。

Release(Int32)

以指定的次数退出信号量并返回前一个计数。

SetAccessControl(SemaphoreSecurity)

设置已命名的系统信号量的访问控制安全性。

ToString()

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

(继承自 Object)
TryOpenExisting(String, Semaphore)

打开指定名称为信号量(如果已经存在),并返回指示操作是否成功的值。

TryOpenExisting(String, SemaphoreRights, Semaphore)

用安全访问权限打开指定名称为信号量(如果已经存在),并返回指示操作是否成功的值。

WaitOne()

阻止当前线程,直到当前 WaitHandle 收到信号。

(继承自 WaitHandle)
WaitOne(Int32)

阻止当前线程,直到当前 WaitHandle 收到信号,同时使用 32 位带符号整数指定时间间隔(以毫秒为单位)。

(继承自 WaitHandle)
WaitOne(Int32, Boolean)

阻止当前线程,直到当前的 WaitHandle 收到信号为止,同时使用 32 位带符号整数指定时间间隔,并指定是否在等待之前退出同步域。

(继承自 WaitHandle)
WaitOne(TimeSpan)

阻止当前线程,直到当前实例收到信号,同时使用 TimeSpan 指定时间间隔。

(继承自 WaitHandle)
WaitOne(TimeSpan, Boolean)

阻止当前线程,直到当前实例收到信号为止,同时使用 TimeSpan 指定时间间隔,并指定是否在等待之前退出同步域。

(继承自 WaitHandle)

显式接口实现

IDisposable.Dispose()

此 API 支持产品基础结构,不能在代码中直接使用。

释放由 WaitHandle 使用的所有资源。

(继承自 WaitHandle)

扩展方法

GetAccessControl(Semaphore)

返回指定的 semaphore 的安全描述符。

SetAccessControl(Semaphore, SemaphoreSecurity)

设置指定信号灯的安全描述符。

GetSafeWaitHandle(WaitHandle)

获取本机操作系统等待句柄的安全句柄。

SetSafeWaitHandle(WaitHandle, SafeWaitHandle)

设置本机操作系统等待句柄的安全句柄。

适用于

线程安全性

此类型是线程安全的。

另请参阅