Mis dos centavos en SpinLock en .Net

Imagine una situación en la que un hilo intenta obtener acceso a un recurso compartido pero el recurso ya está bloqueado, por lo que el hilo tiene que esperar hasta que se libere el bloqueo. Aquí es donde entra en juego la sincronización de hilos. La sincronización de subprocesos se utiliza para evitar que varios subprocesos accedan a un recurso compartido al mismo tiempo. Microsoft .Net Framework proporciona soporte para una variedad de primitivas de sincronización que se pueden usar para controlar el comportamiento del hilo y evitar condiciones de carrera. Mutex y Spinlock son dos mecanismos de sincronización populares que se utilizan para sincronizar el acceso a un recurso compartido.

Un SpinLock es una alternativa para bloquear la sincronización. SpinLock (también conocido como "Busy Waiting") es un mecanismo que se puede utilizar para hacer que un hilo que intenta adquirir un bloqueo espere en un bucle hasta que pueda acceder al recurso. Tenga en cuenta que SpinLock puede funcionar más rápido en comparación con Mutex ya que se reduce el cambio de contexto. Sin embargo, debe usar SpinLocks solo si se supone que la sección crítica debe realizar una cantidad mínima de trabajo, es decir, SpinLock se mantiene durante un período de tiempo muy corto. Los SpinLocks generalmente se prefieren en sistemas multiprocesador simétricos para sondear constantemente la disponibilidad de un recurso en lugar de cambios de contexto.

¿Qué es SpinLock y por qué es necesario?

SpinLock realiza una espera ocupada y puede ofrecer un mejor rendimiento cuando se usa en sistemas de múltiples núcleos, especialmente cuando es barato esperar en un bucle y agrupar un recurso en lugar de bloquearlo. Esto es particularmente útil cuando los tiempos de bloqueo del bloqueo son de corta duración. En otras palabras, puede aprovechar SpinLock en sistemas de múltiples núcleos para reducir la sobrecarga involucrada en el cambio de contexto si el tiempo que se dedicará a la sección crítica es pequeño. Una sección crítica puede definirse como una estructura de datos o un recurso compartido por varios subprocesos, pero uno y solo un subproceso puede tener acceso a él en un momento dado.

Cabe señalar que mantener SpinLock durante más tiempo sería simplemente una pérdida de recursos del sistema y perjudicial para el rendimiento de la aplicación. En esencia, si espera que el bloqueo sea de una duración significativa, SpinLock nunca debe usarse; use SpinLock solo cuando los tiempos de retención del bloqueo sean de una duración razonablemente pequeña.

SpinLock se usa normalmente cuando se trabaja con interrupciones para realizar una espera ocupada dentro de un bucle hasta que el recurso esté disponible. SpinLock no hace que el hilo sea reemplazado, sino que continúa girando hasta que se libera el bloqueo del recurso.

Programando SpinLock en .Net

Tenga en cuenta que un SpinLock se define como una estructura en .Net, es decir, se define como un tipo de valor por razones de rendimiento. Por lo tanto, si está pasando una instancia de SpinLock, debe pasarla por referencia y no por valor. En esta sección exploraremos cómo podemos programar SpinLock en .Net. Para implementar SpinLock en .Net, necesitaría aprovechar la clase SpinLock disponible en el espacio de nombres System.Threading.

La siguiente lista de códigos muestra cómo puede usar SpinLock en .Net.

SpinLock spinLock = new SpinLock (true);

bool isLocked = false;

try

{

spinLock.Enter (ref isLocked);

// Write your usual code here

}

finally

{

if (isLocked)

   spinLock.Exit();

}

SpinWait

Tenga en cuenta que, al igual que SpinLock, SpinWait también es una estructura y no una clase. Al igual que SpinLock, puede utilizar SpinWait para escribir código de sincronización sin bloqueo que pueda "girar" en lugar de bloquear. SpinWait se puede usar para reducir el consumo de recursos al realizar un giro intensivo de la CPU durante 10 iteraciones posteriores, lo que producirá el control llamando a Thread.Yield y Thread.Sleep. En otras palabras, SpinWait se puede usar para limitar el giro intensivo de la CPU a un número fijo de iteraciones. MSDN dice: "System.Threading.SpinWait es un tipo de sincronización ligero que puede usar en escenarios de bajo nivel para evitar los costosos cambios de contexto y las transiciones del kernel que se requieren para los eventos del kernel".

Para usar SpinWait en su código, puede aprovechar el método estático SpinUntil () de la estructura SpinWait o aprovechar su método no estático SpinOnce (). El siguiente fragmento de código ilustra cómo se puede utilizar SpinWait.

SpinWait spinWait = new SpinWait();

bool shouldSpin;

while (!shouldSpin)

{

   Thread.MemoryBarrier(); spinWait.SpinOnce();

}