Este artículo se tradujo automáticamente. Para ver el artículo en inglés, active la casilla Inglés. Además, puede mostrar el texto en inglés en una ventana emergente si mueve el puntero del mouse sobre el texto.
Traducción
Inglés

Clase Monitor

 

Proporciona un mecanismo que sincroniza el acceso a los objetos.

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

System.Object
  System.Threading.Monitor

<ComVisibleAttribute(True)>
<HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization := True,
	ExternalThreading := True)>
Public NotInheritable Class Monitor

NombreDescripción
System_CAPS_pubmethodSystem_CAPS_staticEnter(Object)

Adquiere un bloqueo exclusivo en el objeto especificado.

System_CAPS_pubmethodSystem_CAPS_staticEnter(Object, Boolean)

Adquiere un bloqueo exclusivo en el objeto especificado y establece de forma atómica un valor que indica si se realizó el bloqueo.

System_CAPS_pubmethodSystem_CAPS_staticExit(Object)

Libera un bloqueo exclusivo en el objeto especificado.

System_CAPS_pubmethodSystem_CAPS_staticIsEntered(Object)

Determina si el subproceso actual mantiene el bloqueo en el objeto especificado.

System_CAPS_pubmethodSystem_CAPS_staticPulse(Object)

Notifica un cambio de estado del objeto bloqueado al subproceso que se encuentra en la cola de espera.

System_CAPS_pubmethodSystem_CAPS_staticPulseAll(Object)

Notifica un cambio de estado del objeto a todos los subprocesos que se encuentran en espera.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object)

Intenta adquirir un bloqueo exclusivo en el objeto especificado.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object, Boolean)

Intenta adquirir un bloqueo exclusivo en el objeto especificado y establece de forma atómica un valor que indica si se realizó el bloqueo.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object, Int32)

Intenta adquirir un bloqueo exclusivo en el objeto especificado durante el número de segundos especificado.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object, Int32, Boolean)

Intenta, durante el número especificado de milisegundos, adquirir un bloqueo exclusivo en el objeto especificado y establece de forma atómica un valor que indica si se realizó el bloqueo.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object, TimeSpan)

Intenta adquirir un bloqueo exclusivo en el objeto especificado durante el período de tiempo especificado.

System_CAPS_pubmethodSystem_CAPS_staticTryEnter(Object, TimeSpan, Boolean)

Intenta, durante el periodo de tiempo indicado, adquirir un bloqueo exclusivo en el objeto especificado y establece de forma atómica un valor que indica si se realizó el bloqueo.

System_CAPS_pubmethodSystem_CAPS_staticWait(Object)

Libera el bloqueo en un objeto y bloquea el subproceso actual hasta que vuelve a adquirir el bloqueo.

System_CAPS_pubmethodSystem_CAPS_staticWait(Object, Int32)

Libera el bloqueo en un objeto y bloquea el subproceso actual hasta que vuelve a adquirir el bloqueo. Si transcurre el intervalo de tiempo de espera especificado, el subproceso entra en la cola de subprocesos listos.

System_CAPS_pubmethodSystem_CAPS_staticWait(Object, Int32, Boolean)

Libera el bloqueo en un objeto y bloquea el subproceso actual hasta que vuelve a adquirir el bloqueo. Si transcurre el intervalo de tiempo de espera especificado, el subproceso entra en la cola de subprocesos listos. Este método también especifica si el dominio de sincronización del contexto (si se trata de un contexto sincronizado) sale antes de la espera y vuelve a adquirir el bloqueo después.

System_CAPS_pubmethodSystem_CAPS_staticWait(Object, TimeSpan)

Libera el bloqueo en un objeto y bloquea el subproceso actual hasta que vuelve a adquirir el bloqueo. Si transcurre el intervalo de tiempo de espera especificado, el subproceso entra en la cola de subprocesos listos.

System_CAPS_pubmethodSystem_CAPS_staticWait(Object, TimeSpan, Boolean)

Libera el bloqueo en un objeto y bloquea el subproceso actual hasta que vuelve a adquirir el bloqueo. Si transcurre el intervalo de tiempo de espera especificado, el subproceso entra en la cola de subprocesos listos. De modo opcional, sale del dominio de sincronización del contexto sincronizado antes de la espera y vuelve a adquirir el dominio después.

El Monitor clase le permite sincronizar el acceso a una región de código mediante la obtención y liberación de un bloqueo en un objeto determinado mediante una llamada a la Monitor.Enter, Monitor.TryEnter, y Monitor.Exit métodos. Bloqueos de objeto proporcionan la capacidad para restringir el acceso a un bloque de código, que suele conocerse como una sección crítica. Mientras que un subproceso posee el bloqueo de un objeto, ningún otro subproceso puede adquirir ese bloqueo. También puede usar el Monitor clase para asegurar que ningún otro subproceso tiene permiso para tener acceso a una sección de aplicación de código que se está ejecutando por el propietario del bloqueo, a menos que el otro subproceso está ejecutando el código utilizando un objeto bloqueado distinto.

En este artículo:

La clase de Monitor: información general
El objeto de bloqueo
La sección crítica
Pulse y PulseAll, espera
Monitores y controladores de espera

Monitortiene las siguientes características:

  • Está asociado a un objeto a petición.

  • Es independiente, lo que significa que puede llamarse directamente desde cualquier contexto.

  • Una instancia de la Monitor no se puede crear la clase; los métodos de la Monitor clase son todos estáticos. Cada método se le pasa el objeto sincronizado que controla el acceso a la sección crítica.

System_CAPS_noteNota

Use la Monitor clase a los objetos de bloqueo que no son cadenas (es decir, tipos de referencia distintos de String), no tipos de valor. Para obtener más información, vea las sobrecargas de la Enter método y El objeto de bloqueo sección más adelante en este artículo.

En la tabla siguiente se describe las acciones que pueden realizarse por subprocesos que tienen acceso a objetos sincronizados:

Acción

Descripción

Enter, TryEnter

Adquiere un bloqueo de un objeto. Esta acción también marca el principio de una sección crítica. Ningún otro subproceso puede entrar en la sección crítica, a menos que se ejecuta las instrucciones que aparecen en la sección crítica utilizando un objeto bloqueado distinto.

Wait

Libera el bloqueo en un objeto con el fin de permitir a otros subprocesos bloquear y obtener acceso al objeto. El subproceso que realiza la llamada espera mientras otro subproceso tiene acceso al objeto. Las señales de pulsos se utilizan para notificar a los subprocesos en espera sobre los cambios en el estado de un objeto.

Pulse(señal)PulseAll

Envía una señal a uno o varios subprocesos en espera. La señal notifica a un subproceso en espera que cambió el estado del objeto bloqueado, y el propietario del bloqueo está listo para liberar el bloqueo. El subproceso en espera se coloca en la cola de subprocesos listos del objeto para que pueda recibir el bloqueo para el objeto. Una vez que el subproceso tiene el bloqueo, puede comprobar el nuevo estado del objeto para ver si se ha alcanzado el estado necesario.

Exit

Libera el bloqueo en un objeto. Esta acción también marca el final de una sección crítica protegida por el objeto bloqueado.

A partir del .NET Framework 4, hay dos conjuntos de sobrecargas para el Enter y TryEnter métodos. Un conjunto de sobrecargas tiene un ref (en C#) o ByRef (en Visual Basic) Boolean parámetro que se establece de forma atómica en true si se adquiere el bloqueo, incluso si se produce una excepción al adquirir el bloqueo. Use estas sobrecargas si es crítico para liberar el bloqueo en todos los casos, incluso cuando los recursos que está protegiendo el bloqueo no estén en un estado coherente. 

La clase Monitor consta de static (en C#) o Shared (en Visual Basic) métodos que operan en un objeto que controla el acceso a la sección crítica. Para cada objeto sincronizado, se mantiene la información siguiente:

  • Una referencia al subproceso que actualmente tiene el bloqueo.

  • Una referencia a una cola de subprocesos listos, que contiene los subprocesos que están listos para obtener el bloqueo.

  • Una referencia a una cola de espera, que contiene los subprocesos que están esperando para recibir notificaciones de un cambio en el estado del objeto bloqueado.

Monitor bloquea objetos (es decir, tipos de referencia), no tipos de valor. Aunque puede pasar un tipo de valor a Enter y Exit, se somete a una conversión boxing independiente para cada llamada. Puesto que cada llamada crea un objeto independiente, Enter nunca bloquea y el código al que supuestamente protege no está sincronizado realmente. Además, el objeto que se pasa a Exit es diferente del objeto que se pasa a Enter, por lo que Monitor produce la 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.”.

El siguiente ejemplo ilustra este problema. Inicia diez tareas, cada una de los cuales solo se suspende durante 250 milisegundos. A continuación, cada tarea actualiza una variable de contador, nTasks, pensada para contar el número de tareas que realmente se iniciaron y ejecutaron. Dado que nTasks es una variable global que pueden actualizar varias tareas al mismo tiempo, se usa un monitor para protegerla frente a modificaciones simultáneas de varias tareas. Sin embargo, como muestra la salida del ejemplo, cada una de las tareas produce una excepción SynchronizationLockException.

Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim nTasks As Integer = 0
      Dim tasks As New List(Of Task)()

      Try
         For ctr As Integer = 0 To 9
            tasks.Add(Task.Run( Sub()
                                   ' Instead of doing some work, just sleep.
                                   Thread.Sleep(250)
                                   ' Increment the number of tasks.
                                   Monitor.Enter(nTasks)
                                   Try
                                      nTasks += 1
                                   Finally
                                      Monitor.Exit(nTasks)
                                   End Try
                                End Sub))
         Next
         Task.WaitAll(tasks.ToArray())
         Console.WriteLine("{0} tasks started and executed.", nTasks)
      Catch e As AggregateException
         Dim msg AS String = String.Empty
         For Each ie In e.InnerExceptions
            Console.WriteLine("{0}", ie.GetType().Name)
            If Not msg.Contains(ie.Message) Then
               msg += ie.Message + Environment.NewLine
            End If
         Next
         Console.WriteLine(vbCrLf + "Exception Message(s):")
         Console.WriteLine(msg)
      End Try
   End Sub
End Module
' The example displays the following output:
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'    SynchronizationLockException
'
'    Exception Message(s):
'    Object synchronization method was called from an unsynchronized block of code.

Cada tarea produce una excepción SynchronizationLockException porque la variable nTasks es objeto de a una conversión boxing antes de llamar al método Monitor.Enter en cada tarea. En otras palabras, a cada llamada al método se le pasa una variable independiente, que es independiente del resto. nTasks se vuelve a someter a una conversión boxing en la llamada al método Monitor.Exit. Una vez más, esto crea diez nuevas variables sometidas a conversión boxing, que son independientes entre sí, nTasks, y las diez variables creadas en la llamada al método Monitor.Enter y sometidas a una conversión boxing. A continuación, se produce la excepción porque el código está intentando liberar un bloqueo en una variable recién creada que no se ha bloqueado anteriormente.

Aunque puede aplicar una conversión boxing a una variable de tipo de valor antes de llamar a Enter y Exit, tal como se muestra en el siguiente ejemplo, y pasar el mismo objeto sometido a conversión boxing a ambos métodos, hacerlo no ofrece ninguna ventaja. Los cambios realizados en la variable sometida a conversión unboxing no se reflejan en la copia sometida a conversión boxing, y no hay ninguna forma de cambiar el valor de la copia de sometida a conversión boxing.

Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim nTasks As Integer = 0
      Dim o As Object = nTasks
      Dim tasks As New List(Of Task)()

      Try
         For ctr As Integer = 0 To 9
            tasks.Add(Task.Run( Sub()
                                   ' Instead of doing some work, just sleep.
                                   Thread.Sleep(250)
                                   ' Increment the number of tasks.
                                   Monitor.Enter(o)
                                   Try
                                      nTasks += 1
                                   Finally
                                      Monitor.Exit(o)
                                   End Try
                                End Sub))
         Next
         Task.WaitAll(tasks.ToArray())
         Console.WriteLine("{0} tasks started and executed.", nTasks)
      Catch e As AggregateException
         Dim msg AS String = String.Empty
         For Each ie In e.InnerExceptions
            Console.WriteLine("{0}", ie.GetType().Name)
            If Not msg.Contains(ie.Message) Then
               msg += ie.Message + Environment.NewLine
            End If
         Next
         Console.WriteLine(vbCrLf + "Exception Message(s):")
         Console.WriteLine(msg)
      End Try
   End Sub
End Module
' The example displays the following output:
'       10 tasks started and executed.

Cuando se selecciona un objeto en el que se va a sincronizar, debe bloquear solo en objetos internos o privados. El bloqueo en objetos externos, se podría producir interbloqueos, porque el código relacionado con podría elegir los mismos objetos desea bloquear en para propósitos diferentes.

Tenga en cuenta que puede sincronizar en un objeto en varios dominios de aplicación si el objeto utilizado para el bloqueo deriva de MarshalByRefObject.

Use la Enter y Exit métodos para marcar el principio y al final de una sección crítica.

System_CAPS_noteNota

La funcionalidad proporcionada por el Enter y Exit métodos es idéntica a la que ofrece el bloqueo instrucción en C# y la SyncLock instrucción en Visual Basic, salvo que el lenguaje construye encapsulado el Monitor.Enter(Object, Boolean) sobrecarga del método y la Monitor.Exit método en un try... finally bloque para asegurarse de que se libere el monitor.

Si la sección crítica es un conjunto de instrucciones contiguas, el bloqueo adquirido por el Enter método garantiza que un único subproceso pueda ejecutar el código delimitado con el objeto bloqueado. En este caso, se recomienda colocar ese código en un try bloquear y realizar una llamada a la Exit método en un finally bloque. Esto garantiza la liberación del bloqueo aunque se produzca una excepción. El siguiente fragmento de código muestra este patrón.

' Define the lock object.
Dim obj As New Object()

' Define the critical section.
Monitor.Enter(obj)
Try 
   ' Code to execute one thread at a time.

' catch blocks go here.
Finally 
   Monitor.Exit(obj)
End Try

Esta función normalmente se utiliza para sincronizar el acceso a una variable static o un método de instancia de una clase.

Si una sección crítica abarca todo un método, la utilidad de bloqueo se puede lograr mediante la colocación de la System.Runtime.CompilerServices.MethodImplAttribute en el método y especificando el Synchronized valor en el constructor de System.Runtime.CompilerServices.MethodImplAttribute. Cuando se utiliza este atributo, el Enter y Exit no son necesarias las llamadas a métodos. El siguiente fragmento de código muestra este patrón:

<MethodImplAttribute(MethodImplOptions.Synchronized)>
Sub MethodToLock()
   ' Method implementation.
End Sub 

Tenga en cuenta que el atributo hace que el subproceso actual mantener el bloqueo hasta que el método devuelve; Si el bloqueo puede liberarse antes, utilice la Monitor clase C#, bloqueo instrucción o Visual Basic SyncLock instrucción dentro del método en lugar del atributo.

Aunque es posible que el Enter y Exit instrucciones que bloquear y liberar un objeto determinado puedan atravesar los límites de clase y miembro, no se recomienda esta práctica.

Una vez que un subproceso posee el bloqueo y ha entrado en la sección crítica que protege el bloqueo, puede llamar a la Monitor.Wait, Monitor.Pulse, y Monitor.PulseAll métodos.

WaitLibera el bloqueo si se mantiene, permite que un subproceso en espera o subprocesos para obtener el bloqueo y entrar en la sección crítica y espera a ser notificado por una llamada a la Monitor.Pulse o Monitor.PulseAll método. Cuando Wait recibe la notificación, devuelve y vuelve a obtener el bloqueo.

Tanto Pulse como PulseAll indican al siguiente subproceso de la cola de espera que proceda.

Es importante tener en cuenta la distinción entre el uso de la Monitor clase y WaitHandle objetos.

  • La Monitor clase es puramente administrados, son totalmente portátiles y podrían ser más eficaces en cuanto a requisitos de recursos del sistema operativo.

  • Los objetos WaitHandle representan objetos del sistema operativo que pueden esperar, que son útiles para la sincronización entre el código administrado y el no administrado y exponen algunas características avanzadas del sistema operativo, como la capacidad de esperar muchos objetos a la vez.

En el ejemplo siguiente se usa el Monitor clase para sincronizar el acceso a una sola instancia de un generador de números aleatorios representado por la Random clase. El ejemplo crea diez tareas, cada uno de los cuales se ejecuta de forma asincrónica en un subproceso del grupo. Cada tarea genera números aleatorios 10.000, calcula su Media y dos variables de nivel de procedimiento que mantienen un total acumulado del número de números aleatorios generados y la suma actualiza. Después de que se han ejecutado todas las tareas, estos dos valores, a continuación, se utilizan para calcular la media general.

Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim tasks As New List(Of Task)()
      Dim rnd As New Random()
      Dim total As Long = 0
      Dim n As Integer = 0

      For taskCtr As Integer = 0 To 9
         tasks.Add(Task.Run( Sub()
                                Dim values(9999) As Integer
                                Dim taskTotal As Integer = 0
                                Dim taskN As Integer = 0
                                Dim ctr As Integer = 0
                                Monitor.Enter(rnd)
                                   ' Generate 10,000 random integers.
                                    For ctr = 0 To 9999
                                       values(ctr) = rnd.Next(0, 1001)
                                    Next
                                Monitor.Exit(rnd)
                                taskN = ctr
                                For Each value in values
                                   taskTotal += value
                                Next

                                Console.WriteLine("Mean for task {0,2}: {1:N2} (N={2:N0})",
                                                  Task.CurrentId, taskTotal/taskN,
                                                  taskN)
                                Interlocked.Add(n, taskN)
                                Interlocked.Add(total, taskTotal)
                             End Sub ))
      Next

      Try
         Task.WaitAll(tasks.ToArray())
         Console.WriteLine()
         Console.WriteLine("Mean for all tasks: {0:N2} (N={1:N0})",
                           (total * 1.0)/n, n)
      Catch e As AggregateException
         For Each ie In e.InnerExceptions
            Console.WriteLine("{0}: {1}", ie.GetType().Name, ie.Message)
         Next
      End Try
   End Sub
End Module
' The example displays output like the following:
'       Mean for task  1: 499.04 (N=10,000)
'       Mean for task  2: 500.42 (N=10,000)
'       Mean for task  3: 499.65 (N=10,000)
'       Mean for task  8: 502.59 (N=10,000)
'       Mean for task  5: 502.75 (N=10,000)
'       Mean for task  4: 494.88 (N=10,000)
'       Mean for task  7: 499.22 (N=10,000)
'       Mean for task 10: 496.45 (N=10,000)
'       Mean for task  6: 499.75 (N=10,000)
'       Mean for task  9: 502.79 (N=10,000)
'
'       Mean for all tasks: 499.75 (N=100,000)

Because they can be accessed from any task running on a thread pool thread, access to the variables total and n must also be synchronized. The M:System.Threading.Interlocked.Add(System.Int64@,System.Int64) method is used for this purpose.

En el ejemplo siguiente se muestra el uso combinado de la Monitor clase (implementada con el lock o SyncLock construcción de lenguaje), el Interlocked (clase) y la AutoResetEvent clase. Define dos clases de tipo internal (en C#) o Friend (en Visual Basic), SyncResource y UnSyncResource, que proporcionan respectivamente acceso sincronizado y sin sincronizar a un recurso. Para garantizar que el ejemplo ilustra la diferencia entre el acceso sincronizado y sin sincronizar (podría darse el caso si cada llamada al método se realiza rápidamente), el método incluye un retraso aleatorio: para subprocesos cuya propiedad Thread.ManagedThreadId es par, el método llama a Thread.Sleep para insertar un retraso de 2.000 milisegundos. Tenga en cuenta que, dado que la clase SyncResource no es pública, ninguno de los códigos de cliente tiene un bloqueo en el recurso sincronizado; esto es, la propia clase interna se hace cargo del bloqueo. Esto evita que cualquier código malintencionado se haga cargo de un bloqueo en un objeto público.

Imports System.Threading

Friend Class SyncResource
    ' Use a monitor to enforce synchronization.
    Public Sub Access()
        SyncLock Me
            Console.WriteLine("Staring synchronized resource access on thread #{0}",
                              Thread.CurrentThread.ManagedThreadId)
            If Thread.CurrentThread.ManagedThreadId Mod 2 = 0 Then
                Thread.Sleep(2000)
            End If
            Thread.Sleep(200)
            Console.WriteLine("Stopping synchronized resource access on thread #{0}",
                              Thread.CurrentThread.ManagedThreadId)
        End SyncLock
    End Sub
End Class

Friend Class UnSyncResource
    ' Do not enforce synchronization.
    Public Sub Access()
        Console.WriteLine("Starting unsynchronized esource access on Thread #{0}",
                          Thread.CurrentThread.ManagedThreadId)
        If Thread.CurrentThread.ManagedThreadId Mod 2 = 0 Then
            Thread.Sleep(2000)
        End If
        Thread.Sleep(200)
        Console.WriteLine("Stopping unsynchronized resource access on thread #{0}",
                          Thread.CurrentThread.ManagedThreadId)
    End Sub
End Class

Public Module App
    Private numOps As Integer
    Private opsAreDone As New AutoResetEvent(False)
    Private SyncRes As New SyncResource()
    Private UnSyncRes As New UnSyncResource()

    Public Sub Main()
        ' Set the number of synchronized calls.
        numOps = 5
        For ctr As Integer = 0 To 4
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf SyncUpdateResource))
        Next
        ' Wait until this WaitHandle is signaled.
        opsAreDone.WaitOne()
        Console.WriteLine(vbTab + vbNewLine + "All synchronized operations have completed.")
        Console.WriteLine()

        numOps = 5
        ' Reset the count for unsynchronized calls.
        For ctr As Integer = 0 To 4
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf UnSyncUpdateResource))
        Next

        ' Wait until this WaitHandle is signaled.
        opsAreDone.WaitOne()
        Console.WriteLine(vbTab + vbNewLine + "All unsynchronized thread operations have completed.")
    End Sub

    Sub SyncUpdateResource()
        ' Call the internal synchronized method.
        SyncRes.Access()

        ' Ensure that only one thread can decrement the counter at a time.
        If Interlocked.Decrement(numOps) = 0 Then
            ' Announce to Main that in fact all thread calls are done.
            opsAreDone.Set()
        End If
    End Sub

    Sub UnSyncUpdateResource()
        ' Call the unsynchronized method.
        UnSyncRes.Access()

        ' Ensure that only one thread can decrement the counter at a time.
        If Interlocked.Decrement(numOps) = 0 Then
            ' Announce to Main that in fact all thread calls are done.
            opsAreDone.Set()
        End If
    End Sub
End Module
' The example displays output like the following:
'    Staring synchronized resource access on thread #6
'    Stopping synchronized resource access on thread #6
'    Staring synchronized resource access on thread #7
'    Stopping synchronized resource access on thread #7
'    Staring synchronized resource access on thread #3
'    Stopping synchronized resource access on thread #3
'    Staring synchronized resource access on thread #4
'    Stopping synchronized resource access on thread #4
'    Staring synchronized resource access on thread #5
'    Stopping synchronized resource access on thread #5
'
'    All synchronized operations have completed.
'
'    Starting unsynchronized esource access on Thread #7
'    Starting unsynchronized esource access on Thread #9
'    Starting unsynchronized esource access on Thread #10
'    Starting unsynchronized esource access on Thread #6
'    Starting unsynchronized esource access on Thread #3
'    Stopping unsynchronized resource access on thread #7
'    Stopping unsynchronized resource access on thread #9
'    Stopping unsynchronized resource access on thread #3
'    Stopping unsynchronized resource access on thread #10
'    Stopping unsynchronized resource access on thread #6
'
'    All unsynchronized thread operations have completed.

The example defines a variable, numOps, that defines the number of threads that will attempt to access the resource. The application thread calls the M:System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback) method for synchronized and unsynchronized access five times each. The M:System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback) method has a single parameter, a delegate that accepts no parameters and returns no value. For synchronized access, it invokes the SyncUpdateResource method; for unsynchronized access, it invokes the UnSyncUpdateResource method. After each set of method calls, the application thread calls the AutoResetEvent.WaitOnehttps://msdn.microsoft.com/library/58195swd.aspx method so that it blocks until the T:System.Threading.AutoResetEvent instance is signaled.

Each call to the SyncUpdateResource method calls the internal SyncResource.Access method and then calls the M:System.Threading.Interlocked.Decrement(System.Int64@) method to decrement the numOps counter. The M:System.Threading.Interlocked.Decrement(System.Int64@) method Is used to decrement the counter, because otherwise you cannot be certain that a second thread will access the value before a first thread's decremented value has been stored in the variable. When the last synchronized worker thread decrements the counter to zero, indicating that all synchronized threads have completed accessing the resource, the SyncUpdateResource method calls the EventWaitHandle.Sethttps://msdn.microsoft.com/library/system.threading.eventwaithandle.set.aspx method, which signals the main thread to continue execution.

Each call to the UnSyncUpdateResource method calls the internal UnSyncResource.Access method and then calls the M:System.Threading.Interlocked.Decrement(System.Int64@) method to decrement the numOps counter. Once again, the M:System.Threading.Interlocked.Decrement(System.Int64@) method Is used to decrement the counter to ensure that a second thread does not access the value before a first thread's decremented value has been assigned to the variable. When the last unsynchronized worker thread decrements the counter to zero, indicating that no more unsynchronized threads need to access the resource, the UnSyncUpdateResource method calls the EventWaitHandle.Sethttps://msdn.microsoft.com/library/system.threading.eventwaithandle.set.aspx method, which signals the main thread to continue execution.

As the output from the example shows, synchronized access ensures that the calling thread exits the protected resource before another thread can access it; each thread waits on its predecessor. On the other hand, without the lock, the UnSyncResource.Access method is called in the order in which threads reach it.

Plataforma universal de Windows
Disponible desde 8
.NET Framework
Disponible desde 1.1
Biblioteca de clases portable
Se admite en: plataformas portátiles de .NET
Silverlight
Disponible desde 2.0
Windows Phone Silverlight
Disponible desde 7.0
Windows Phone
Disponible desde 8.1

Este tipo es seguro para la ejecución de subprocesos.

Volver al principio
Mostrar: