Semaphore (Clase)
Limita el número de subprocesos que pueden tener acceso a un recurso o grupo de recursos simultáneamente.

Espacio de nombres: System.Threading
Ensamblado: System (en system.dll)

Sintaxis

Visual Basic (Declaración)
<ComVisibleAttribute(False)> _
Public NotInheritable Class Semaphore
    Inherits WaitHandle
Visual Basic (Uso)
Dim instance As Semaphore
C#
[ComVisibleAttribute(false)] 
public sealed class Semaphore : WaitHandle
C++
[ComVisibleAttribute(false)] 
public ref class Semaphore sealed : public WaitHandle
J#
/** @attribute ComVisibleAttribute(false) */ 
public final class Semaphore extends WaitHandle
JScript
ComVisibleAttribute(false) 
public final class Semaphore extends WaitHandle
XAML
No aplicable.
Comentarios

NotaNota:

El atributo HostProtectionAttribute aplicado a esta clase tiene el valor de propiedad Resources siguiente: Synchronization | ExternalThreading. HostProtectionAttribute no afecta a las aplicaciones de escritorio (que normalmente se inician al hacer doble clic en un icono, escribir un comando o escribir una dirección URL en un explorador). Para obtener más información, vea la clase HostProtectionAttribute o Programación de SQL Server y atributos de protección del host.

Utilice la clase Semaphore para controlar el acceso a un grupo de recursos. Para entrar en el semáforo, los subprocesos llaman al método WaitOne, que se hereda de la clase WaitHandle, y para liberarlo llaman al método Release.

El recuento de un semáforo disminuye cada vez que un subproceso entra en él, e incrementa cuando un subproceso lo libera. Cuando el recuento es cero, las solicitudes posteriores se bloquean hasta que otros subprocesos liberan el semáforo. Cuando todos los subprocesos han liberado el semáforo, el recuento está en el valor máximo especificado al crear el semáforo.

No hay ningún orden garantizado, como FIFO o LIFO, para la entrada de los subprocesos bloqueados en el semáforo.

Un subproceso puede entrar varias veces en el semáforo, mediante llamadas al método WaitOne. Para liberar algunas de estas entradas o todas ellas, el subproceso puede llamar varias veces a la sobrecarga del método Release sin parámetros, o bien a la sobrecarga del método Release(Int32), que especifica el número de entradas que se liberan.

La clase Semaphore no exige la identidad del subproceso en las llamadas a WaitOne o Release. Es responsabilidad del programador garantizar que los subprocesos no liberen el semáforo demasiadas veces. Por ejemplo, supongamos que un semáforo tiene un recuento máximo de dos y que entran en el semáforo los subprocesos A y B. Si un error de programación del subproceso B hace que llame a Release dos veces, las dos llamadas tienen éxito. Se alcanza el recuento máximo del semáforo y, si el subproceso A llama posteriormente a Release, se genera una excepción SemaphoreFullException.

Los semáforos son de dos tipos: semáforos locales y semáforos de sistema con nombre. Si crea un objeto Semaphore mediante un constructor que acepta un nombre, se asocia a un semáforo del sistema operativo con ese nombre. Los semáforos de sistema con nombre son visibles en todo el sistema operativo y se pueden utilizar para sincronizar las actividades de los procesos. Puede crear varios objetos Semaphore que representan el mismo semáforo de sistema con nombre y, para abrir un semáforo de sistema con nombre ya existente, puede utilizar el método OpenExisting.

Un semáforo local sólo existe dentro del proceso. Puede utilizarlo cualquier subproceso del proceso que contenga una referencia al objeto Semaphore local. Cada objeto Semaphore es un semáforo local distinto.

Ejemplo

En el ejemplo de código siguiente se crea un semáforo con un número máximo de tres y un recuento inicial de cero. El ejemplo inicia cinco subprocesos que se bloquean en espera del semáforo. El subproceso principal aumenta el recuento del semáforo a su máximo, mediante la sobrecarga del método Release(Int32), lo que permite la entrada de tres subprocesos en el semáforo. Los subprocesos utilizan el método System.Threading.Thread.Sleep para esperar un segundo, simular que trabajan y, a continuación, llamar a la sobrecarga de método Release para liberar el semáforo. Cada vez que se libera el semáforo, se muestra el recuento del semáforo anterior. Los mensajes de consola llevan un seguimiento del uso del semáforo. El intervalo de trabajo simulado aumenta ligeramente por cada subproceso, lo que facilita la lectura del resultado.

Visual Basic
Imports System
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
C#
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(0, 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(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());
    }
}
C++
#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() );
   }
};
J#
import System.*;
import 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(String[] args)
    {
        // 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 (int i = 1; i <= 5; i++) {
            System.Threading.Thread t = new System.Threading.Thread(new 
                ParameterizedThreadStart(Worker));
            // Start the thread, passing the number.
            //
            t.Start((Int32)i);
        }
        // Wait for half a second, to allow all the
        // threads to start and to block on the semaphore.
        //
        System.Threading.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.");
    } //main

    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(_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.
        //
        System.Threading.Thread.Sleep(1000 + padding);

        Console.WriteLine("Thread {0} releases the semaphore.", num);
        Console.WriteLine("Thread {0} previous semaphore count: {1}", num, 
            (Int32)_pool.Release());
    } //Worker
} //Example
Jerarquía de herencia

System.Object
   System.MarshalByRefObject
     System.Threading.WaitHandle
      System.Threading.Semaphore
Seguridad para subprocesos

Los miembros estáticos públicos (Shared en Visual Basic) de este tipo son seguros para la ejecución de subprocesos. No se garantiza que los miembros de instancias sean seguros para la ejecución de subprocesos.
Plataformas

Windows 98, Windows 2000 Service Pack 4, Windows Millennium, Windows Server 2003, Windows XP Media Center, Windows XP Professional x64, Windows XP SP2, Windows XP Starter

Microsoft .NET Framework 3.0 es compatible con Windows Vista, Microsoft Windows XP SP2 y Windows Server 2003 SP1.

Información de versión

.NET Framework

Compatible con: 3.0, 2.0
Vea también

Page view tracker