Semaphore y SemaphoreSlim

La clase System.Threading.Semaphore representa un semáforo local o con nombre (para todo el sistema). Es un contenedor fino alrededor del objeto semáforo de Win32. Los semáforos de Win32 son semáforos con recuento, que se pueden utilizar para controlar el acceso a un grupo de recursos.

La clase SemaphoreSlim representa un semáforo ligero y rápido que se puede utilizar para esperar dentro de un proceso único cuando se prevé que los tiempos de espera sean muy cortos. SemaphoreSlim confía en la medida de lo posible en las primitivas de sincronización proporcionadas por Common Language Runtime (CLR). Sin embargo, también proporciona de forma diferida identificadores de espera inicializados y basados en kernel si son necesarios para permitir la espera en varios semáforos. SemaphoreSlim también admite el uso de tokens de cancelación, pero no admite semáforos con nombre o el uso de un identificador de espera para sincronización.

Administrar un recurso limitado

Los subprocesos entran en el semáforo llamando al método WaitOne, que se hereda de la clase WaitHandle. Cuando la llamada vuelve, disminuye el recuento en el semáforo. Cuando un subproceso solicita la entrada y el recuento es cero, el subproceso se bloquea. Cuando los subprocesos liberan el semáforo llamando al método Semaphore.Release, se permite la entrada a los subprocesos bloqueados. No hay ningún orden garantizado, como primero en entrar, primero en salir (FIFO) o último en entrar, primero en salir (LIFO), por el que los subprocesos bloqueados entren en el semáforo.

Un subproceso puede entrar varias veces en el semáforo llamando repetidamente al método WaitOne. Para liberar el semáforo, el subproceso puede llamar a la sobrecarga del método Release() el mismo número de veces o, si no, puede llamar a la sobrecarga del método Release(Int32) y especificar el número de entradas que quiere liberar.

Los semáforos y la identidad del subproceso

La clase Semaphore no exige la identidad del subproceso en las llamadas a los métodos WaitOne y Release. Por ejemplo, un escenario habitual de uso de los semáforos implica la existencia de un subproceso productor y un subproceso consumidor, donde uno de los subprocesos siempre incrementa el recuento del semáforo y el otro siempre lo disminuye.

Es responsabilidad del programador garantizar que un subproceso no libere el semáforo demasiadas veces. Por ejemplo, imagine un semáforo que tiene un recuento máximo de dos y en el que entran un subproceso A y un subproceso B. Si un error de programación del subproceso B hace que llame a Release dos veces, las dos llamadas tienen éxito. El recuento del semáforo está completo y cuando finalmente el subproceso A llama al método Release, se produce una excepción SemaphoreFullException.

Semáforos con nombre

El sistema operativo Windows permite que los semáforos tengan nombres. Un semáforo con nombre es un semáforo para todo el sistema. Es decir, una vez creado el semáforo con nombre, éste es visible para todos los subprocesos de todos los procesos. Así, se puede utilizar un semáforo con nombre para sincronizar las actividades tanto de procesos como de subprocesos.

Puede crear un objeto Semaphore que represente un semáforo de sistema con nombre utilizando uno de los constructores que especifica un nombre.

NotaNota

Dado que los semáforos con nombre son semáforos para todo el sistema, es posible tener varios objetos Semaphore que representen el mismo semáforo con nombre.Cada vez que se llama a un constructor o al método Semaphore.OpenExisting, se crea un nuevo objeto Semaphore.Si se especifica el mismo nombre repetidas veces, se crean varios objetos que representan el mismo semáforo con nombre.

Tenga el cuidado al utilizar los semáforos con nombre. Dado que son semáforos para todo el sistema, puede ocurrir que otro proceso que utilice el mismo nombre entre inesperadamente en el semáforo. Cualquier código malintencionado ejecutado en el mismo equipo podría utilizar esto como base de un ataque por denegación de servicio.

Utilice la seguridad de control de acceso para proteger un objeto Semaphore que represente un semáforo con nombre, preferentemente utilizando un constructor que especifique un objeto System.Security.AccessControl.SemaphoreSecurity. También puede aplicar la seguridad de control de acceso mediante el método Semaphore.SetAccessControl, aunque este sistema dejará un espacio de vulnerabilidad entre el momento en que se crea el semáforo y el momento en que se protege. Proteger los semáforos con seguridad de control de acceso ayuda a evitar ataques malintencionados, pero no resuelve el problema de los conflictos de nombres no intencionados.

Vea también

Referencia

Semaphore

SemaphoreSlim

Otros recursos

Objetos y características de subprocesos