Exportar (0) Imprimir
Expandir todo
Este artículo proviene de un motor de traducción automática. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Monitores

Los objetos Monitor exponen la capacidad de sincronizar el acceso a una región de código tomando y liberando un bloqueo de un objeto concreto mediante los métodos Monitor.Enter, Monitor.TryEnter y Monitor.Exit. Una vez que se tenga un bloqueo en una región del código, se podrán usar los métodos Monitor.Wait, Monitor.Pulse y Monitor.PulseAll. Wait libera el bloqueo si este se mantiene y espera recibir una notificación. Cuando el método Wait recibe la notificación, devuelve y obtiene de nuevo el bloqueo. Ambos métodos, Pulse y PulseAll avisan al siguiente subproceso de la cola de espera de que puede continuar.

Las instrucciones SyncLock de Visual Basic y lock de C# utilizan Monitor.Enter para realizar el bloqueo y Monitor.Exit para liberarlo. La ventaja de utilizar las instrucciones de un lenguaje es que todo lo que esté incluido en el bloqueo lock o SyncLock está incluido en una instrucción Try. La instrucción Try tiene un bloque Finally para garantizar que se libera el bloqueo.

Monitor bloquea objetos (es decir, tipos de referencia), no tipos de valor. Aunque puede pasar un tipo de valor a Enter y Exit, la conversión boxing se aplica por separado en cada llamada. Como cada llamada crea un objeto independiente, Enter nunca se bloquea, y el código que supuestamente está protegiendo no está en realidad sincronizado. Además, el objeto que se pasa a Exit es distinto del objeto que se pasa a Enter, por tanto, Monitor inicia una excepción SynchronizationLockException con el mensaje "El método de sincronización del objeto se ha llamado desde un bloque de códigos sin sincronizar". En el siguiente ejemplo se ilustran estos problemas.


try
{
    int x = 1;
    // The call to Enter() creates a generic synchronizing object for the value
    // of x each time the code is executed, so that Enter never blocks.
    Monitor.Enter(x);
    try
    {
        // Code that needs to be protected by the monitor.
    }
    finally
    {
        // Always use Finally to ensure that you exit the Monitor.

        // The call to Exit() will FAIL!!!
        // The synchronizing object created for x in Exit() will be different
        // than the object used in Enter(). SynchronizationLockException
        // will be thrown.
        Monitor.Exit(x);
    }
}
catch (SynchronizationLockException SyncEx)
{
    Console.WriteLine("A SynchronizationLockException occurred. Message:");
    Console.WriteLine(SyncEx.Message);
}


Aunque se puede aplicar una conversión boxing a una variable de tipo de valor antes de llamar a Enter y a Exit, tal y como se muestra en el ejemplo siguiente, y pasar el mismo objeto al que se le ha aplicado la conversión boxing a los dos métodos, hacerlo no reporta ningún beneficio. Los cambios en la variable no se reflejan en la copia a la que se aplica la conversión boxing y no hay ninguna forma de cambiar el valor de esta copia.


int x = 1;
object o = x;

Monitor.Enter(o);
try
{
    // Code that needs to be protected by the monitor.
}
finally
{
    // Always use Finally to ensure that you exit the Monitor.
    Monitor.Exit(o);
}


Es importante tener en cuenta la distinción entre el uso de objetos Monitor y WaitHandle. Los objetos Monitor están estrictamente administrados, son totalmente portátiles y podrían ser más eficaces en lo que respecta a los requisitos de recursos del sistema operativo. Los objetos WaitHandle representan objetos de espera del sistema operativo, son útiles para la sincronización entre código administrado y no administrado, y exponen algunas características avanzadas del sistema operativo, como la capacidad de esperar varios objetos a la vez.

En el ejemplo de código siguiente se muestra el uso combinado de la clase Monitor (implementada con las instrucciones del compilador lock y SyncLock), la clase Interlocked y la clase AutoResetEvent.


using System;
using System.Threading;

// Note: The class whose internal public member is the synchronizing
// method is not public; none of the client code takes a lock on the
// Resource object.The member of the nonpublic class takes the lock on
// itself. Written this way, malicious code cannot take a lock on
// a public object.
class SyncResource
{
    public void Access(Int32 threadNum)
    {
        // Uses Monitor class to enforce synchronization.
        lock (this)
        {
            // Synchronized: Despite the next conditional, each thread
            // waits on its predecessor.
            if (threadNum % 2 == 0)
            {
                Thread.Sleep(2000);
            }
            Console.WriteLine("Start Synched Resource access (Thread={0})", threadNum);
            Thread.Sleep(200);
            Console.WriteLine("Stop Synched Resource access  (Thread={0})", threadNum);
        }
    }
}

// Without the lock, the method is called in the order in which threads reach it.
class UnSyncResource
{
    public void Access(Int32 threadNum)
    {
        // Does not use Monitor class to enforce synchronization.
        // The next call throws the thread order.
        if (threadNum % 2 == 0)
        {
            Thread.Sleep(2000);
        }
        Console.WriteLine("Start UnSynched Resource access (Thread={0})", threadNum);
        Thread.Sleep(200);
        Console.WriteLine("Stop UnSynched Resource access  (Thread={0})", threadNum);
    }
}

public class App
{
    static Int32 numAsyncOps = 5;
    static AutoResetEvent asyncOpsAreDone = new AutoResetEvent(false);
    static SyncResource SyncRes = new SyncResource();
    static UnSyncResource UnSyncRes = new UnSyncResource();

    public static void Main()
    {
        for (Int32 threadNum = 0; threadNum < 5; threadNum++)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(SyncUpdateResource), threadNum);
        }

        // Wait until this WaitHandle is signaled.
        asyncOpsAreDone.WaitOne();
        Console.WriteLine("\t\nAll synchronized operations have completed.\t\n");

        // Reset the thread count for unsynchronized calls.
        numAsyncOps = 5;

        for (Int32 threadNum = 0; threadNum < 5; threadNum++)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(UnSyncUpdateResource), threadNum);
        }

        // Wait until this WaitHandle is signaled.
        asyncOpsAreDone.WaitOne();
        Console.WriteLine("\t\nAll unsynchronized thread operations have completed.");
    }

    // The callback method's signature MUST match that of a
    // System.Threading.TimerCallback delegate (it takes an Object
    // parameter and returns void).
    static void SyncUpdateResource(Object state)
    {
        // This calls the internal synchronized method, passing
        // a thread number.
        SyncRes.Access((Int32) state);

        // Count down the number of methods that the threads have called.
        // This must be synchronized, however; you cannot know which thread
        // will access the value **before** another thread's incremented
        // value has been stored into the variable.
        if (Interlocked.Decrement(ref numAsyncOps) == 0)
        {
            // Announce to Main that in fact all thread calls are done.
            asyncOpsAreDone.Set();
        }
    }

    // The callback method's signature MUST match that of a
    // System.Threading.TimerCallback delegate (it takes an Object
    // parameter and returns void).
    static void UnSyncUpdateResource(Object state)
    {
        // This calls the unsynchronized method, passing a thread number.
        UnSyncRes.Access((Int32) state);

        // Count down the number of methods that the threads have called.
        // This must be synchronized, however; you cannot know which thread
        // will access the value **before** another thread's incremented
        // value has been stored into the variable.
        if (Interlocked.Decrement(ref numAsyncOps) == 0)
        {
            // Announce to Main that in fact all thread calls are done.
            asyncOpsAreDone.Set();
        }
    }
}


Adiciones de comunidad

AGREGAR
Mostrar:
© 2014 Microsoft