Monitor.TryEnter Método

Definição

Tenta adquirir um bloqueio exclusivo no objeto especificado.

Sobrecargas

Nome Description
TryEnter(Object, TimeSpan, Boolean)

Tenta, pela quantidade de tempo especificada, adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

TryEnter(Object, Int32, Boolean)

Tenta, para o número especificado de milissegundos, adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

TryEnter(Object, TimeSpan)

Tenta, pela quantidade de tempo especificada, adquirir um bloqueio exclusivo no objeto especificado.

TryEnter(Object, Boolean)

Tenta adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

TryEnter(Object)

Tenta adquirir um bloqueio exclusivo no objeto especificado.

TryEnter(Object, Int32)

Tenta, para o número especificado de milissegundos, adquirir um bloqueio exclusivo no objeto especificado.

TryEnter(Object, TimeSpan, Boolean)

Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs

Tenta, pela quantidade de tempo especificada, adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

public:
 static void TryEnter(System::Object ^ obj, TimeSpan timeout, bool % lockTaken);
public static void TryEnter(object obj, TimeSpan timeout, ref bool lockTaken);
static member TryEnter : obj * TimeSpan * bool -> unit
Public Shared Sub TryEnter (obj As Object, timeout As TimeSpan, ByRef lockTaken As Boolean)

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

timeout
TimeSpan

A quantidade de tempo para aguardar o bloqueio. Um valor de -1 milissegundo especifica uma espera infinita.

lockTaken
Boolean

O resultado da tentativa de adquirir o bloqueio, passado por referência. A entrada deve ser false. A saída será true se o bloqueio for adquirido; caso contrário, a saída será false. A saída é definida mesmo se ocorrer uma exceção durante a tentativa de adquirir o bloqueio.

Exceções

A entrada a ser lockTakentrue.

O obj parâmetro é null.

O valor de timeout em milissegundos é negativo e não é igual a Infinite (-1 milissegundos) ou é maior que Int32.MaxValue.

Comentários

Se o valor do timeout parâmetro convertido em milissegundos for igual a -1, esse método será equivalente a Enter(Object). Se o valor igual a timeout 0 for igual a 0, esse método será equivalente a TryEnter(Object).

Se o bloqueio não tiver sido feito porque uma exceção foi gerada, a variável especificada para o parâmetro será false após o lockTaken término desse método. Isso permite que o programa determine, em todos os casos, se é necessário liberar o bloqueio.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter mais informações, consulte o tópico da Monitor classe.

Para garantir que o thread não insira a seção crítica, examine o valor e lockTaken execute o código na seção crítica somente se o valor for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();
var timeout = TimeSpan.FromMilliseconds(500);
bool lockTaken = false;

try {
   Monitor.TryEnter(lockObj, timeout, ref lockTaken);
   if (lockTaken) {
      // The critical section.
   }
   else {
      // The lock was not acquired.
   }
}
finally {
   // Ensure that the lock is released.
   if (lockTaken) {
      Monitor.Exit(lockObj);
   }
}
Dim lockObj As New Object()
Dim timeout = TimeSpan.FromMilliseconds(500)
Dim lockTaken As Boolean = False

Try
   Monitor.TryEnter(lockObj, timeout, lockTaken)
   If lockTaken Then
      ' The critical section.
   Else
      ' The lock was not acquired.
   End If
Finally
   ' Ensure that the lock is released.
   If lockTaken Then Monitor.Exit(lockObj)
End Try

Confira também

Aplica-se a

TryEnter(Object, Int32, Boolean)

Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs

Tenta, para o número especificado de milissegundos, adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

public:
 static void TryEnter(System::Object ^ obj, int millisecondsTimeout, bool % lockTaken);
public static void TryEnter(object obj, int millisecondsTimeout, ref bool lockTaken);
static member TryEnter : obj * int * bool -> unit
Public Shared Sub TryEnter (obj As Object, millisecondsTimeout As Integer, ByRef lockTaken As Boolean)

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

millisecondsTimeout
Int32

O número de milissegundos a aguardar pelo bloqueio.

lockTaken
Boolean

O resultado da tentativa de adquirir o bloqueio, passado por referência. A entrada deve ser false. A saída será true se o bloqueio for adquirido; caso contrário, a saída será false. A saída é definida mesmo se ocorrer uma exceção durante a tentativa de adquirir o bloqueio.

Exceções

A entrada a ser lockTakentrue.

O obj parâmetro é null.

millisecondsTimeout é negativo e não é igual a Infinite.

Exemplos

O código a seguir mostra o padrão básico para usar a sobrecarga do TryEnter(Object, Boolean) método. Essa sobrecarga sempre define o valor da variável que é passada para o parâmetro ref (ByRef em Visual Basic) lockTaken, mesmo que o método gere uma exceção, portanto, o valor da variável é uma maneira confiável de testar se o bloqueio deve ser liberado.

bool acquiredLock = false;

try
{
    Monitor.TryEnter(lockObject, 500, ref acquiredLock);
    if (acquiredLock)
    {

        // Code that accesses resources that are protected by the lock.
    }
    else
    {
    
        // Code to deal with the fact that the lock was not acquired.
    }
}
finally
{
    if (acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}
Dim acquiredLock As Boolean = False

Try
    Monitor.TryEnter(lockObject, 500, acquiredLock)
    If acquiredLock Then

        ' Code that accesses resources that are protected by the lock.

    Else

        ' Code to deal with the fact that the lock was not acquired.

    End If
Finally
    If acquiredLock Then
        Monitor.Exit(lockObject)
    End If
End Try

Comentários

Se o millisecondsTimeout parâmetro for Infiniteigual, esse método será equivalente a Enter(Object). Se millisecondsTimeout for igual a 0, esse método será equivalente a TryEnter(Object).

Se o bloqueio não tiver sido feito porque uma exceção foi gerada, a variável especificada para o parâmetro será false após o lockTaken término desse método. Isso permite que o programa determine, em todos os casos, se é necessário liberar o bloqueio.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter mais informações, consulte o tópico da Monitor classe.

Para garantir que o thread não insira a seção crítica, examine o valor e lockTaken execute o código na seção crítica somente se o valor for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();
int timeout = 500;
bool lockTaken = false;

try {
   Monitor.TryEnter(lockObj, timeout, ref lockTaken);
   if (lockTaken) {
      // The critical section.
   }
   else {
      // The lock was not acquired.
   }
}
finally {
   // Ensure that the lock is released.
   if (lockTaken) {
      Monitor.Exit(lockObj);
   }   
}
Dim lockObj As New Object()
Dim timeout As Integer = 500
Dim lockTaken As Boolean = False

Try
   Monitor.TryEnter(lockObj, timeout, lockTaken)
   If lockTaken Then
      ' The critical section.
   Else
      ' The lock was not acquired.
   End If
Finally
   ' Ensure that the lock is released.
   If lockTaken Then Monitor.Exit(lockObj)
End Try

Aplica-se a

TryEnter(Object, TimeSpan)

Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs
Origem:
Monitor.cs

Tenta, pela quantidade de tempo especificada, adquirir um bloqueio exclusivo no objeto especificado.

public:
 static bool TryEnter(System::Object ^ obj, TimeSpan timeout);
public static bool TryEnter(object obj, TimeSpan timeout);
static member TryEnter : obj * TimeSpan -> bool
Public Shared Function TryEnter (obj As Object, timeout As TimeSpan) As Boolean

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

timeout
TimeSpan

Um TimeSpan que representa a quantidade de tempo para aguardar o bloqueio. Um valor de -1 milissegundo especifica uma espera infinita.

Retornos

true se o thread atual adquirir o bloqueio; caso contrário, false.

Exceções

O obj parâmetro é null.

O valor de timeout em milissegundos é negativo e não é igual a Infinite (-1 milissegundos) ou é maior que Int32.MaxValue.

Comentários

Se o valor do timeout parâmetro convertido em milissegundos for igual a -1, esse método será equivalente a Enter. Se o valor igual a timeout 0 for igual a 0, esse método será equivalente a TryEnter.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter detalhes, consulte o tópico da Monitor classe.

Para garantir que o thread não insira a seção crítica, examine o valor retornado do método e execute o código na seção crítica somente se o valor retornado for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();
var timeout = TimeSpan.FromMilliseconds(500);

if (Monitor.TryEnter(lockObj, timeout)) {
   try {
      // The critical section.
   }
   finally {
      // Ensure that the lock is released.
      Monitor.Exit(lockObj);
   }
}
else {
   // The lock was not acquired.
}
Dim lockObj As New Object()
Dim timeout = TimeSpan.FromMilliseconds(500)

If Monitor.TryEnter(lockObj, timeout) Then
   Try
      ' The critical section.
   Finally
      ' Ensure that the lock is released.
      Monitor.Exit(lockObj)
   End Try
Else
   ' The lock was not acquired.
End If

Confira também

Aplica-se a

TryEnter(Object, Boolean)

Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs

Tenta adquirir um bloqueio exclusivo no objeto especificado e define atomicamente um valor que indica se o bloqueio foi feito.

public:
 static void TryEnter(System::Object ^ obj, bool % lockTaken);
public static void TryEnter(object obj, ref bool lockTaken);
static member TryEnter : obj * bool -> unit
Public Shared Sub TryEnter (obj As Object, ByRef lockTaken As Boolean)

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

lockTaken
Boolean

O resultado da tentativa de adquirir o bloqueio, passado por referência. A entrada deve ser false. A saída será true se o bloqueio for adquirido; caso contrário, a saída será false. A saída é definida mesmo se ocorrer uma exceção durante a tentativa de adquirir o bloqueio.

Exceções

A entrada a ser lockTakentrue.

O obj parâmetro é null.

Exemplos

O código a seguir mostra o padrão básico para usar a sobrecarga do TryEnter(Object, Boolean) método. Essa sobrecarga sempre define o valor da variável que é passada para o parâmetro ref (ByRef em Visual Basic) lockTaken, mesmo que o método gere uma exceção, portanto, o valor da variável é uma maneira confiável de testar se o bloqueio deve ser liberado.

bool acquiredLock = false;

try
{
    Monitor.TryEnter(lockObject, ref acquiredLock);
    if (acquiredLock)
    {

        // Code that accesses resources that are protected by the lock.
    }
    else
    {
    
        // Code to deal with the fact that the lock was not acquired.
    }
}
finally
{
    if (acquiredLock)
    {
        Monitor.Exit(lockObject);
    }
}
Dim acquiredLock As Boolean = False

Try
    Monitor.TryEnter(lockObject, acquiredLock)
    If acquiredLock Then

        ' Code that accesses resources that are protected by the lock.

    Else

        ' Code to deal with the fact that the lock was not acquired.

    End If
Finally
    If acquiredLock Then
        Monitor.Exit(lockObject)
    End If
End Try

Comentários

Se bem-sucedido, esse método adquire um bloqueio exclusivo no obj parâmetro. Esse método retorna imediatamente, se o bloqueio está disponível ou não.

Se o bloqueio não tiver sido feito porque uma exceção foi gerada, a variável especificada para o parâmetro será false após o lockTaken término desse método. Isso permite que o programa determine, em todos os casos, se é necessário liberar o bloqueio.

Esse método é semelhante a Enter(Object, Boolean), mas nunca bloqueará o thread atual. Se o thread não puder entrar sem bloquear, o lockTaken argumento será definido para false quando o método retornar.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter mais informações, consulte o Monitor artigo.

Para garantir que o thread não insira a seção crítica, examine o valor e lockTaken execute o código na seção crítica somente se o valor for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();
bool lockTaken = false;

try {
   Monitor.TryEnter(lockObj, ref lockTaken); 
   if (lockTaken) {
      // The critical section.
   }
   else {
      // The lock was not acquired.
   }
}
finally {
   // Ensure that the lock is released.
   if (lockTaken) {
      Monitor.Exit(lockObj);
   }
}
Dim lockObj As New Object()
Dim lockTaken As Boolean = False

Try 
   Monitor.TryEnter(lockObj, lockTaken) 
   If lockTaken Then
      ' The critical section.
   Else 
      ' The lock was not acquired.
   End If
Finally 
   ' Ensure that the lock is released.
   If lockTaken Then Monitor.Exit(lockObj)
End Try

Aplica-se a

TryEnter(Object)

Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs

Tenta adquirir um bloqueio exclusivo no objeto especificado.

public:
 static bool TryEnter(System::Object ^ obj);
public static bool TryEnter(object obj);
static member TryEnter : obj -> bool
Public Shared Function TryEnter (obj As Object) As Boolean

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

Retornos

true se o thread atual adquirir o bloqueio; caso contrário, false.

Exceções

O obj parâmetro é null.

Exemplos

O exemplo de código a seguir demonstra como usar o TryEnter método.

using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;

class SafeQueue<T>
{
   // A queue that is protected by Monitor.
   private Queue<T> m_inputQueue = new Queue<T>();

   // Lock the queue and add an element.
   public void Enqueue(T qValue)
   {
      // Request the lock, and block until it is obtained.
      Monitor.Enter(m_inputQueue);
      try
      {
         // When the lock is obtained, add an element.
         m_inputQueue.Enqueue(qValue);
      }
      finally
      {
         // Ensure that the lock is released.
         Monitor.Exit(m_inputQueue);
      }
   }

   // Try to add an element to the queue: Add the element to the queue
   // only if the lock is immediately available.
   public bool TryEnqueue(T qValue)
   {
      // Request the lock.
      if (Monitor.TryEnter(m_inputQueue))
      {
         try
         {
            m_inputQueue.Enqueue(qValue);
         }
         finally
         {
            // Ensure that the lock is released.
            Monitor.Exit(m_inputQueue);
         }
         return true;
      }
      else
      {
         return false;
      }
   }

   // Try to add an element to the queue: Add the element to the queue
   // only if the lock becomes available during the specified time
   // interval.
   public bool TryEnqueue(T qValue, int waitTime)
   {
      // Request the lock.
      if (Monitor.TryEnter(m_inputQueue, waitTime))
      {
         try
         {
            m_inputQueue.Enqueue(qValue);
         }
         finally
         {
            // Ensure that the lock is released.
            Monitor.Exit(m_inputQueue);
         }
         return true;
      }
      else
      {
         return false;
      }
   }

   // Lock the queue and dequeue an element.
   public T Dequeue()
   {
      T retval;

      // Request the lock, and block until it is obtained.
      Monitor.Enter(m_inputQueue);
      try
      {
         // When the lock is obtained, dequeue an element.
         retval = m_inputQueue.Dequeue();
      }
      finally
      {
         // Ensure that the lock is released.
         Monitor.Exit(m_inputQueue);
      }

      return retval;
   }

   // Delete all elements that equal the given object.
   public int Remove(T qValue)
   {
      int removedCt = 0;

      // Wait until the lock is available and lock the queue.
      Monitor.Enter(m_inputQueue);
      try
      {
         int counter = m_inputQueue.Count;
         while (counter > 0)
            // Check each element.
         {
            T elem = m_inputQueue.Dequeue();
            if (!elem.Equals(qValue))
            {
               m_inputQueue.Enqueue(elem);
            }
            else
            {
               // Keep a count of items removed.
               removedCt += 1;
            }
            counter = counter - 1;
         }
      }
      finally
      {
         // Ensure that the lock is released.
         Monitor.Exit(m_inputQueue);
      }

      return removedCt;
   }

   // Print all queue elements.
   public string PrintAllElements()
   {
      StringBuilder output = new StringBuilder();

      // Lock the queue.
      Monitor.Enter(m_inputQueue);
      try
      {
         foreach( T elem in m_inputQueue )
         {
            // Print the next element.
            output.AppendLine(elem.ToString());
         }
      }
      finally
      {
         // Ensure that the lock is released.
         Monitor.Exit(m_inputQueue);
      }

      return output.ToString();
   }
}

public class Example
{
   private static SafeQueue<int> q = new SafeQueue<int>();
   private static int threadsRunning = 0;
   private static int[][] results = new int[3][];

   static void Main()
   {
      Console.WriteLine("Working...");

      for(int i = 0; i < 3; i++)
      {
         Thread t = new Thread(ThreadProc);
         t.Start(i);
         Interlocked.Increment(ref threadsRunning);
      }
   }

   private static void ThreadProc(object state)
   {
      DateTime finish = DateTime.Now.AddSeconds(10);
      Random rand = new Random();
      int[] result = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
      int threadNum = (int) state;

      while (DateTime.Now < finish)

      {
         int what = rand.Next(250);
         int how = rand.Next(100);

         if (how < 16)
         {
            q.Enqueue(what);
            result[(int)ThreadResultIndex.EnqueueCt] += 1;
         }
         else if (how < 32)
         {
            if (q.TryEnqueue(what))
            {
               result[(int)ThreadResultIndex.TryEnqueueSucceedCt] += 1;
            }
            else
            {
               result[(int)ThreadResultIndex.TryEnqueueFailCt] += 1;
            }
         }
         else if (how < 48)
         {
            // Even a very small wait significantly increases the success
            // rate of the conditional enqueue operation.
            if (q.TryEnqueue(what, 10))
            {
               result[(int)ThreadResultIndex.TryEnqueueWaitSucceedCt] += 1;
            }
            else
            {
               result[(int)ThreadResultIndex.TryEnqueueWaitFailCt] += 1;
            }
         }
         else if (how < 96)
         {
            result[(int)ThreadResultIndex.DequeueCt] += 1;
            try
            {
               q.Dequeue();
            }
            catch
            {
               result[(int)ThreadResultIndex.DequeueExCt] += 1;
            }
         }
         else
         {
            result[(int)ThreadResultIndex.RemoveCt] += 1;
            result[(int)ThreadResultIndex.RemovedCt] += q.Remove(what);
         }
      }

      results[threadNum] = result;

      if (0 == Interlocked.Decrement(ref threadsRunning))
      {
         StringBuilder sb = new StringBuilder(
            "                               Thread 1 Thread 2 Thread 3    Total\n");

         for(int row = 0; row < 9; row++)
         {
            int total = 0;
            sb.Append(titles[row]);

            for(int col = 0; col < 3; col++)
            {
               sb.Append(String.Format("{0,9}", results[col][row]));
               total += results[col][row];
            }

            sb.AppendLine(String.Format("{0,9}", total));
         }

         Console.WriteLine(sb.ToString());
      }
   }

   private static string[] titles = {
      "Enqueue                       ",
      "TryEnqueue succeeded          ",
      "TryEnqueue failed             ",
      "TryEnqueue(T, wait) succeeded ",
      "TryEnqueue(T, wait) failed    ",
      "Dequeue attempts              ",
      "Dequeue exceptions            ",
      "Remove operations             ",
      "Queue elements removed        "};

   private enum ThreadResultIndex
   {
      EnqueueCt,
      TryEnqueueSucceedCt,
      TryEnqueueFailCt,
      TryEnqueueWaitSucceedCt,
      TryEnqueueWaitFailCt,
      DequeueCt,
      DequeueExCt,
      RemoveCt,
      RemovedCt
   };
}

/* This example produces output similar to the following:

Working...
                               Thread 1 Thread 2 Thread 3    Total
Enqueue                          277382   515209   308464  1101055
TryEnqueue succeeded             276873   514621   308099  1099593
TryEnqueue failed                   109      181      134      424
TryEnqueue(T, wait) succeeded    276913   514434   307607  1098954
TryEnqueue(T, wait) failed            2        0        0        2
Dequeue attempts                 830980  1544081   924164  3299225
Dequeue exceptions                12102    21589    13539    47230
Remove operations                 69550   129479    77351   276380
Queue elements removed            11957    22572    13043    47572
 */
Imports System.Threading
Imports System.Collections.Generic
Imports System.Text

Class SafeQueue(Of T)

   ' A queue that is protected by Monitor.
   Private m_inputQueue As New Queue(Of T)

   ' Lock the queue and add an element.
   Public Sub Enqueue(ByVal qValue As T)

      ' Request the lock, and block until it is obtained.
      Monitor.Enter(m_inputQueue)
      Try
         ' When the lock is obtained, add an element.
         m_inputQueue.Enqueue(qValue)

      Finally
         ' Ensure that the lock is released.
         Monitor.Exit(m_inputQueue)
      End Try
   End Sub

   ' Try to add an element to the queue: Add the element to the queue 
   ' only if the lock is immediately available.
   Public Function TryEnqueue(ByVal qValue As T) As Boolean

      ' Request the lock.
      If Monitor.TryEnter(m_inputQueue) Then
         Try
            m_inputQueue.Enqueue(qValue)

         Finally
            ' Ensure that the lock is released.
            Monitor.Exit(m_inputQueue)
         End Try
         Return True
      Else
         Return False
      End If
   End Function

   ' Try to add an element to the queue: Add the element to the queue 
   ' only if the lock becomes available during the specified time
   ' interval.
   Public Function TryEnqueue(ByVal qValue As T, ByVal waitTime As Integer) As Boolean

      ' Request the lock.
      If Monitor.TryEnter(m_inputQueue, waitTime) Then
         Try
            m_inputQueue.Enqueue(qValue)

         Finally
            ' Ensure that the lock is released.
            Monitor.Exit(m_inputQueue)
         End Try
         Return True
      Else
         Return False
      End If
   End Function

   ' Lock the queue and dequeue an element.
   Public Function Dequeue() As T

      Dim retval As T

      ' Request the lock, and block until it is obtained.
      Monitor.Enter(m_inputQueue)
      Try
         ' When the lock is obtained, dequeue an element.
         retval = m_inputQueue.Dequeue()

      Finally
         ' Ensure that the lock is released.
         Monitor.Exit(m_inputQueue)
      End Try

      Return retval
   End Function

   ' Delete all elements that equal the given object.
   Public Function Remove(ByVal qValue As T) As Integer

      Dim removedCt As Integer = 0

      ' Wait until the lock is available and lock the queue.
      Monitor.Enter(m_inputQueue)
      Try
         Dim counter As Integer = m_inputQueue.Count
         While (counter > 0)
            'Check each element.
            Dim elem As T = m_inputQueue.Dequeue()
            If Not elem.Equals(qValue) Then
               m_inputQueue.Enqueue(elem)
            Else
               ' Keep a count of items removed.
               removedCt += 1
            End If
            counter = counter - 1
         End While

      Finally
         ' Ensure that the lock is released.
         Monitor.Exit(m_inputQueue)
      End Try

      Return removedCt
   End Function

   ' Print all queue elements.
   Public Function PrintAllElements() As String

      Dim output As New StringBuilder()

      'Lock the queue.
      Monitor.Enter(m_inputQueue)
      Try
         For Each elem As T In m_inputQueue
            ' Print the next element.
            output.AppendLine(elem.ToString())
         Next

      Finally
         ' Ensure that the lock is released.
         Monitor.Exit(m_inputQueue)
      End Try

      Return output.ToString()
   End Function
End Class

Public Class Example

   Private Shared q As New SafeQueue(Of Integer)
   Private Shared threadsRunning As Integer = 0
   Private Shared results(2)() As Integer

   Friend Shared Sub Main()

      Console.WriteLine("Working...")

      For i As Integer = 0 To 2

         Dim t As New Thread(AddressOf ThreadProc)
         t.Start(i)
         Interlocked.Increment(threadsRunning)

      Next i

   End Sub

   Private Shared Sub ThreadProc(ByVal state As Object)

      Dim finish As DateTime = DateTime.Now.AddSeconds(10)
      Dim rand As New Random()
      Dim result() As Integer = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
      Dim threadNum As Integer = CInt(state)

      While (DateTime.Now < finish)

         Dim what As Integer = rand.Next(250)
         Dim how As Integer = rand.Next(100)

         If how < 16 Then
            q.Enqueue(what)
            result(ThreadResultIndex.EnqueueCt) += 1
         Else If how < 32 Then
            If q.TryEnqueue(what)
               result(ThreadResultIndex.TryEnqueueSucceedCt) += 1
            Else
               result(ThreadResultIndex.TryEnqueueFailCt) += 1
            End If
         Else If how < 48 Then
            ' Even a very small wait significantly increases the success 
            ' rate of the conditional enqueue operation.
            If q.TryEnqueue(what, 10)
               result(ThreadResultIndex.TryEnqueueWaitSucceedCt) += 1
            Else
               result(ThreadResultIndex.TryEnqueueWaitFailCt) += 1
            End If
         Else If how < 96 Then
            result(ThreadResultIndex.DequeueCt) += 1
            Try
               q.Dequeue()
            Catch
               result(ThreadResultIndex.DequeueExCt) += 1
            End Try
         Else
            result(ThreadResultIndex.RemoveCt) += 1
            result(ThreadResultIndex.RemovedCt) += q.Remove(what)
         End If
         
      End While

      results(threadNum) = result

      If 0 = Interlocked.Decrement(threadsRunning) Then
      
         Dim sb As New StringBuilder( _
            "                               Thread 1 Thread 2 Thread 3    Total" & vbLf)

         For row As Integer = 0 To 8

            Dim total As Integer = 0
            sb.Append(titles(row))

            For col As Integer = 0 To 2

               sb.Append(String.Format("{0,9}", results(col)(row)))
               total += results(col)(row)

            Next col

            sb.AppendLine(String.Format("{0,9}", total))

         Next row

         Console.WriteLine(sb.ToString())

      End If     
    
   End Sub

   Private Shared titles() As String = { _
      "Enqueue                       ", _
      "TryEnqueue succeeded          ", _
      "TryEnqueue failed             ", _
      "TryEnqueue(T, wait) succeeded ", _
      "TryEnqueue(T, wait) failed    ", _
      "Dequeue attempts              ", _
      "Dequeue exceptions            ", _
      "Remove operations             ", _
      "Queue elements removed        "  _
   }

   Private Enum ThreadResultIndex
      EnqueueCt
      TryEnqueueSucceedCt
      TryEnqueueFailCt
      TryEnqueueWaitSucceedCt
      TryEnqueueWaitFailCt
      DequeueCt
      DequeueExCt
      RemoveCt
      RemovedCt
   End Enum

End Class

' This example produces output similar to the following:
'
'Working...
'                               Thread 1 Thread 2 Thread 3    Total
'Enqueue                          294357   512164   302838  1109359
'TryEnqueue succeeded             294486   512403   303117  1110006
'TryEnqueue failed                   108      234      127      469
'TryEnqueue(T, wait) succeeded    294259   512796   302556  1109611
'TryEnqueue(T, wait) failed            1        1        1        3
'Dequeue attempts                 882266  1537993   907795  3328054
'Dequeue exceptions                12691    21474    13480    47645
'Remove operations                 74059   128715    76187   278961
'Queue elements removed            12667    22606    13219    48492

Comentários

Se bem-sucedido, esse método adquire um bloqueio exclusivo no obj parâmetro. Esse método retorna imediatamente, se o bloqueio está disponível ou não.

Esse método é semelhante a Enter, mas nunca bloqueará o thread atual. Se o thread não puder entrar sem bloqueio, o método retornará false,.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter detalhes, consulte o Monitor artigo.

Para garantir que o thread não insira a seção crítica, examine o valor retornado do método e execute o código na seção crítica somente se o valor retornado for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();

if (Monitor.TryEnter(lockObj)) {
   try {
      // The critical section.
   }
   finally {
      // Ensure that the lock is released.
      Monitor.Exit(lockObj);
   }
}
else {
   // The lock was not axquired.
}
Dim lockObj As New Object()

If Monitor.TryEnter(lockObj) Then
   Try
      ' The critical section.
   Finally
      ' Ensure that the lock is released.
      Monitor.Exit(lockObj)
   End Try
Else
   ' The lock was not acquired.
End If

Confira também

Aplica-se a

TryEnter(Object, Int32)

Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs
Origem:
Monitor.CoreCLR.cs

Tenta, para o número especificado de milissegundos, adquirir um bloqueio exclusivo no objeto especificado.

public:
 static bool TryEnter(System::Object ^ obj, int millisecondsTimeout);
public static bool TryEnter(object obj, int millisecondsTimeout);
static member TryEnter : obj * int -> bool
Public Shared Function TryEnter (obj As Object, millisecondsTimeout As Integer) As Boolean

Parâmetros

obj
Object

O objeto no qual adquirir o bloqueio.

millisecondsTimeout
Int32

O número de milissegundos a aguardar pelo bloqueio.

Retornos

true se o thread atual adquirir o bloqueio; caso contrário, false.

Exceções

O obj parâmetro é null.

millisecondsTimeout é negativo e não é igual a Infinite.

Comentários

Se o millisecondsTimeout parâmetro for Infiniteigual, esse método será equivalente a Enter. Se millisecondsTimeout for igual a 0, esse método será equivalente a TryEnter.

Note

Use Monitor para bloquear objetos (ou seja, tipos de referência), não tipos de valor. Para obter detalhes, consulte o Monitor artigo.

Para garantir que o thread não insira a seção crítica, examine o valor retornado do método e execute o código na seção crítica somente se o valor retornado for true. O fragmento de código a seguir mostra o padrão usado para chamar esse método. Observe que você deve chamar Exit em um finally bloco para garantir que o thread de chamada libere seu bloqueio na seção crítica se ocorrer uma exceção.

var lockObj = new Object();
int timeout = 500;

if (Monitor.TryEnter(lockObj, timeout)) {
   try {
      // The critical section.
   }
   finally {
      // Ensure that the lock is released.
      Monitor.Exit(lockObj);
   }
}
else {
   // The lock was not acquired.
}
Dim lockObj As New Object()
Dim timeout As Integer = 500

If Monitor.TryEnter(lockObj, timeout) Then
   Try
      ' The critical section.
   Finally
      ' Ensure that the lock is released.
      Monitor.Exit(lockObj)
   End Try
Else
   ' The lock was not acquired.
End If

Confira também

Aplica-se a