Para ver el artículo en inglés, active la casilla Inglés. También puede ver el texto en inglés en una ventana emergente si pasa el puntero del mouse por el texto.
Traducción
Inglés

SpinWait

.NET Framework (current version)
 

System.Threading.SpinWait es un tipo de sincronización ligero que se puede utilizar en escenarios de bajo nivel para evitar los costosos cambios de contexto y las transiciones del kernel que se requieren para los eventos de kernel. En los equipos de varios núcleos, cuando no se espera que un recurso sea retenido durante períodos de tiempo prolongados, puede ser más eficaz que un subproceso en espera gire en modo usuario durante unas docenas o centenares de ciclos y, a continuación, vuelva a intentar adquirir el recurso. Si el recurso está disponible después de girar, habremos ahorrado varios miles de ciclos. Si el recurso todavía no está disponible, solamente habremos gastado unos cuantos ciclos e igualmente podemos entrar en una espera basada en kernel. Esta combinación de giro y espera se denomina en ocasiones operación de espera de dos fases.

SpinWait se ha diseñado para utilizarlo en combinación con los tipos de .NET Framework que contienen eventos de kernel, como ManualResetEvent. SpinWait también se puede utilizar por sí solo para la funcionalidad del giro básica en un único programa.

SpinWait es más que un bucle vacío sin más. Se ha implementado con todo cuidado para proporcionar un comportamiento de giro correcto para el caso general e iniciará por sí mismo cambios de contexto si gira durante el tiempo suficiente (aproximadamente, el tiempo necesario para una transición del kernel). Por ejemplo, en los equipos de un núcleo, SpinWait cede de inmediato el intervalo de tiempo del subproceso, porque al girar se bloquea el progreso de avance en todos los subprocesos. SpinWait también cede el paso incluso en equipos de varios núcleos, para evitar que el subproceso en espera bloquee otros subprocesos de más prioridad o el recolector de elementos no utilizados. Por consiguiente, si utiliza SpinWait en una operación de espera de dos fases, recomendamos que invoque la espera del kernel antes de que SpinWait inicie un cambio de contexto. SpinWait proporciona la propiedad NextSpinWillYield, que puede comprobar antes de cada llamada a SpinOnce. Cuando la propiedad devuelve true, inicie su propia operación de espera. Para obtener un ejemplo, vea How to: Use SpinWait to Implement a Two-Phase Wait Operation.

Si no está realizando una operación de espera de dos fases, sino que se limita a girar hasta que se cumpla alguna condición, puede permitir que SpinWait realice sus cambios de contexto para que se comporte correctamente en el entorno del sistema operativo Windows. El siguiente ejemplo básico muestra un objeto SpinWait en una pila sin bloqueo. Si necesita una pila segura para subprocesos de alto rendimiento, considere la posibilidad de usar System.Collections.Concurrent.ConcurrentStack<T>.

public class LockFreeStack<T>
{
    private volatile Node m_head;

    private class Node { public Node Next; public T Value; }

    public void Push(T item)
    {
        var spin = new SpinWait();
        Node node = new Node { Value = item }, head;
        while (true)
        {
            head = m_head;
            node.Next = head;
            if (Interlocked.CompareExchange(ref m_head, node, head) == head) break;
            spin.SpinOnce();
        }
    }

    public bool TryPop(out T result)
    {
        result = default(T);
        var spin = new SpinWait();

        Node head;
        while (true)
        {
            head = m_head;
            if (head == null) return false;
            if (Interlocked.CompareExchange(ref m_head, head.Next, head) == head)
            {
                result = head.Value;
                return true;
            }
            spin.SpinOnce();
        }
    }
}
Mostrar: