Monitor 클래스

정의

개체에 대한 액세스를 동기화하는 메커니즘을 제공합니다.Provides a mechanism that synchronizes access to objects.

public ref class Monitor abstract sealed
public ref class Monitor sealed
public static class Monitor
public sealed class Monitor
[System.Runtime.InteropServices.ComVisible(true)]
public static class Monitor
type Monitor = class
[<System.Runtime.InteropServices.ComVisible(true)>]
type Monitor = class
Public Class Monitor
Public NotInheritable Class Monitor
상속
Monitor
특성

예제

다음 예제에서는 클래스를 사용 하 여 Monitor 클래스가 나타내는 난수 생성기의 단일 인스턴스에 대 한 액세스를 동기화 합니다 Random .The following example uses the Monitor class to synchronize access to a single instance of a random number generator represented by the Random class. 이 예제에서는 각각 스레드 풀 스레드에서 비동기적으로 실행 되는 10 개의 작업을 만듭니다.The example creates ten tasks, each of which executes asynchronously on a thread pool thread. 각 태스크는 1만 난수를 생성 하 고 평균을 계산 하며 생성 된 난수 수와 합계를 유지 하는 두 프로시저 수준 변수를 업데이트 합니다.Each task generates 10,000 random numbers, calculates their average, and updates two procedure-level variables that maintain a running total of the number of random numbers generated and their sum. 모든 작업이 실행 된 후이 두 값은 전체 평균을 계산 하는 데 사용 됩니다.After all tasks have executed, these two values are then used to calculate the overall mean.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      List<Task> tasks = new List<Task>();
      Random rnd = new Random();
      long total = 0;
      int n = 0;
      
      for (int taskCtr = 0; taskCtr < 10; taskCtr++)
         tasks.Add(Task.Run( () => {  int[] values = new int[10000];
                                      int taskTotal = 0;
                                      int taskN = 0;
                                      int ctr = 0;
                                      Monitor.Enter(rnd);
                                         // Generate 10,000 random integers
                                         for (ctr = 0; ctr < 10000; ctr++)
                                            values[ctr] = rnd.Next(0, 1001);
                                      Monitor.Exit(rnd);
                                      taskN = ctr;
                                      foreach (var value in values)
                                         taskTotal += value;

                                      Console.WriteLine("Mean for task {0,2}: {1:N2} (N={2:N0})",
                                                        Task.CurrentId, (taskTotal * 1.0)/taskN,
                                                        taskN);
                                      Interlocked.Add(ref n, taskN);
                                      Interlocked.Add(ref total, taskTotal);
                                    } ));
      try {
         Task.WaitAll(tasks.ToArray());
         Console.WriteLine("\nMean for all tasks: {0:N2} (N={1:N0})",
                           (total * 1.0)/n, n);
      }
      catch (AggregateException e) {
         foreach (var ie in e.InnerExceptions)
            Console.WriteLine("{0}: {1}", ie.GetType().Name, ie.Message);
      }
   }
}
// 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)
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)

스레드 풀 스레드에서 실행 되는 모든 작업에서 액세스할 수 있으므로 변수에 대 total 한 액세스 n 도 동기화 해야 합니다.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. Interlocked.Add메서드는 이러한 용도로 사용 됩니다.The Interlocked.Add method is used for this purpose.

다음 예제에서는 Monitor 클래스 ( lock 또는 SyncLock 언어 구문으로 구현), Interlocked 클래스 및 AutoResetEvent 클래스를 결합 하 여 사용 하는 방법을 보여 줍니다.The following example demonstrates the combined use of the Monitor class (implemented with the lock or SyncLock language construct), the Interlocked class, and the AutoResetEvent class. internal Friend 클래스 SyncResource UnSyncResource 는 리소스에 대 한 동기화 된 액세스와 동기화 되지 않은 액세스를 각각 제공 하는 두 개의 (c #의 경우) 또는 (Visual Basic) 클래스를 정의 합니다.It defines two internal (in C#) or Friend (in Visual Basic) classes, SyncResource and UnSyncResource, that respectively provide synchronized and unsynchronized access to a resource. 예제가 동기화 된 액세스와 동기화 되지 않은 액세스 (각 메서드 호출이 빠르게 완료 되는 경우) 간의 차이점을 보여 주기 위해 메서드에 임의 지연이 포함 됩니다. 속성이 짝수 인 스레드의 경우 Thread.ManagedThreadId 메서드는 Thread.Sleep 를 호출 하 여 2000 밀리초의 지연을 도입 합니다.To ensure that the example illustrates the difference between the synchronized and unsynchronized access (which could be the case if each method call completes rapidly), the method includes a random delay: for threads whose Thread.ManagedThreadId property is even, the method calls Thread.Sleep to introduce a delay of 2,000 milliseconds. SyncResource클래스는 public이 아니므로 클라이언트 코드는 동기화 된 리소스에 대 한 잠금을 사용 하지 않습니다. 내부 클래스 자체는 잠금을 사용 합니다.Note that, because the SyncResource class is not public, none of the client code takes a lock on the synchronized resource; the internal class itself takes the lock. 이렇게 하면 악의적인 코드가 공용 개체에 대 한 잠금을 수행 하지 않습니다.This prevents malicious code from taking a lock on a public object.

using System;
using System.Threading;

internal class SyncResource
{
    // Use a monitor to enforce synchronization.
    public void Access()
    {
        lock(this) {
            Console.WriteLine("Starting synchronized resource access on thread #{0}",
                              Thread.CurrentThread.ManagedThreadId);
            if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
                Thread.Sleep(2000);

            Thread.Sleep(200);
            Console.WriteLine("Stopping synchronized resource access on thread #{0}",
                              Thread.CurrentThread.ManagedThreadId);
        }
    }
}

internal class UnSyncResource
{
    // Do not enforce synchronization.
    public void Access()
    {
        Console.WriteLine("Starting unsynchronized resource access on Thread #{0}",
                          Thread.CurrentThread.ManagedThreadId);
        if (Thread.CurrentThread.ManagedThreadId % 2 == 0)
            Thread.Sleep(2000);

        Thread.Sleep(200);
        Console.WriteLine("Stopping unsynchronized resource access on thread #{0}",
                          Thread.CurrentThread.ManagedThreadId);
    }
}

public class App
{
    private static int numOps;
    private static AutoResetEvent opsAreDone = new AutoResetEvent(false);
    private static SyncResource SyncRes = new SyncResource();
    private static UnSyncResource UnSyncRes = new UnSyncResource();

   public static void Main()
   {
        // Set the number of synchronized calls.
        numOps = 5;
        for (int ctr = 0; ctr <= 4; ctr++)
            ThreadPool.QueueUserWorkItem(new WaitCallback(SyncUpdateResource));

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

        // Reset the count for unsynchronized calls.
        numOps = 5;
        for (int ctr = 0; ctr <= 4; ctr++)
            ThreadPool.QueueUserWorkItem(new WaitCallback(UnSyncUpdateResource));

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

    static void SyncUpdateResource(Object state)
    {
        // Call the internal synchronized method.
        SyncRes.Access();

        // Ensure that only one thread can decrement the counter at a time.
        if (Interlocked.Decrement(ref numOps) == 0)
            // Announce to Main that in fact all thread calls are done.
            opsAreDone.Set();
    }

    static void UnSyncUpdateResource(Object state)
    {
        // Call the unsynchronized method.
        UnSyncRes.Access();

        // Ensure that only one thread can decrement the counter at a time.
        if (Interlocked.Decrement(ref numOps) == 0)
            // Announce to Main that in fact all thread calls are done.
            opsAreDone.Set();
    }
}
// The example displays output like the following:
//    Starting synchronized resource access on thread #6
//    Stopping synchronized resource access on thread #6
//    Starting synchronized resource access on thread #7
//    Stopping synchronized resource access on thread #7
//    Starting synchronized resource access on thread #3
//    Stopping synchronized resource access on thread #3
//    Starting synchronized resource access on thread #4
//    Stopping synchronized resource access on thread #4
//    Starting synchronized resource access on thread #5
//    Stopping synchronized resource access on thread #5
//
//    All synchronized operations have completed.
//
//    Starting unsynchronized resource access on Thread #7
//    Starting unsynchronized resource access on Thread #9
//    Starting unsynchronized resource access on Thread #10
//    Starting unsynchronized resource access on Thread #6
//    Starting unsynchronized resource 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.
Imports System.Threading

Friend Class SyncResource
    ' Use a monitor to enforce synchronization.
    Public Sub Access()
        SyncLock Me
            Console.WriteLine("Starting 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 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 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 + Environment.NewLine + "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 + Environment.NewLine + "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:
'    Starting synchronized resource access on thread #6
'    Stopping synchronized resource access on thread #6
'    Starting synchronized resource access on thread #7
'    Stopping synchronized resource access on thread #7
'    Starting synchronized resource access on thread #3
'    Stopping synchronized resource access on thread #3
'    Starting synchronized resource access on thread #4
'    Stopping synchronized resource access on thread #4
'    Starting synchronized resource access on thread #5
'    Stopping synchronized resource access on thread #5
'
'    All synchronized operations have completed.
'
'    Starting unsynchronized resource access on Thread #7
'    Starting unsynchronized resource access on Thread #9
'    Starting unsynchronized resource access on Thread #10
'    Starting unsynchronized resource access on Thread #6
'    Starting unsynchronized resource 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.

이 예제에서는 numOps 리소스에 액세스 하려고 하는 스레드 수를 정의 하는 변수를 정의 합니다.The example defines a variable, numOps, that defines the number of threads that will attempt to access the resource. 애플리케이션 스레드는 동기화된 액세스와 동기화되지 않은 액세스에 대해 각각 5번씩 ThreadPool.QueueUserWorkItem(WaitCallback) 메서드를 호출합니다.The application thread calls the ThreadPool.QueueUserWorkItem(WaitCallback) method for synchronized and unsynchronized access five times each. 메서드에는 매개 변수를 ThreadPool.QueueUserWorkItem(WaitCallback) 허용 하지 않으며 값을 반환 하지 않는 대리자 인 단일 매개 변수가 있습니다.The ThreadPool.QueueUserWorkItem(WaitCallback) method has a single parameter, a delegate that accepts no parameters and returns no value. 동기화 된 액세스의 경우 메서드를 호출 하 고, 동기화 되지 않은 SyncUpdateResource 액세스의 경우 메서드를 호출 합니다 UnSyncUpdateResource .For synchronized access, it invokes the SyncUpdateResource method; for unsynchronized access, it invokes the UnSyncUpdateResource method. 호출 애플리케이션 스레드가 각 일련의 메서드 호출 후는 AutoResetEvent.WaitOne 될 때까지 차단 한다는 메서드는 AutoResetEvent 인스턴스가 신호입니다.After each set of method calls, the application thread calls the AutoResetEvent.WaitOne method so that it blocks until the AutoResetEvent instance is signaled.

메서드에 대 한 각 호출은 SyncUpdateResource 내부 메서드를 호출한 SyncResource.Access 다음 메서드를 호출 Interlocked.Decrement 하 여 카운터를 감소 시킵니다 numOps .Each call to the SyncUpdateResource method calls the internal SyncResource.Access method and then calls the Interlocked.Decrement method to decrement the numOps counter. Interlocked.Decrement메서드는 카운터를 감소 하는 데 사용 됩니다. 그렇지 않으면 첫 번째 스레드의 감소 된 값이 변수에 저장 되기 전에 두 번째 스레드가 해당 값에 액세스 하는 것을 확신할 수 없습니다.The Interlocked.Decrement 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. 마지막으로 동기화 된 작업자 스레드가 카운터를 0으로 감소 시켜 동기화 된 모든 스레드가 해당 리소스에 대 한 액세스를 완료 했음을 나타내는 경우 메서드는 메서드를 호출 하 여 SyncUpdateResource EventWaitHandle.Set 주 스레드가 계속 실행 되도록 신호를 보냅니다.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.Set method, which signals the main thread to continue execution.

메서드에 대 한 각 호출은 UnSyncUpdateResource 내부 메서드를 호출한 UnSyncResource.Access 다음 메서드를 호출 Interlocked.Decrement 하 여 카운터를 감소 시킵니다 numOps .Each call to the UnSyncUpdateResource method calls the internal UnSyncResource.Access method and then calls the Interlocked.Decrement method to decrement the numOps counter. 다시 한 번 메서드를 사용 하 여 Interlocked.Decrement 첫 번째 스레드의 감소 된 값이 변수에 할당 되기 전에 두 번째 스레드가 해당 값에 액세스 하지 않도록 카운터를 감소 시킵니다.Once again, the Interlocked.Decrement 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. 마지막으로 동기화 되지 않은 작업자 스레드가 카운터를 0으로 감소 시켜 리소스에 액세스 해야 하는 동기화 되지 않은 스레드가 더 이상 없음을 나타내는 경우 메서드는 메서드를 호출 하 여 UnSyncUpdateResource EventWaitHandle.Set 주 스레드가 계속 실행 되도록 신호를 보냅니다.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.Set 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. 반면에 잠금이 없으면 UnSyncResource.Access 메서드가 스레드에 도달 하는 순서 대로 호출 됩니다.On the other hand, without the lock, the UnSyncResource.Access method is called in the order in which threads reach it.

설명

Monitor클래스를 사용 하면 Monitor.Enter , Monitor.TryEnter 및 메서드를 호출 하 여 특정 개체에 대 한 잠금을 가져오고 해제 하 여 코드 영역에 대 한 액세스를 동기화 할 수 있습니다 Monitor.Exit .The Monitor class allows you to synchronize access to a region of code by taking and releasing a lock on a particular object by calling the Monitor.Enter, Monitor.TryEnter, and Monitor.Exit methods. 개체 잠금은 주로 임계 영역 이라고 하는 코드 블록에 대 한 액세스를 제한 하는 기능을 제공 합니다.Object locks provide the ability to restrict access to a block of code, commonly called a critical section. 스레드에서 개체에 대 한 잠금을 소유 하는 동안에는 다른 스레드가 해당 잠금을 획득할 수 없습니다.While a thread owns the lock for an object, no other thread can acquire that lock. 사용할 수도 있습니다는 Monitor 다른 스레드가 애플리케이션의 섹션에 액세스할 수 있는지 확인 하는 클래스 잠금 소유자에 의해 실행 되 고 다른 스레드가 잠겨 있는 다른 개체를 사용 하는 코드를 실행 중인 경우가 아니면 코드입니다.You can also use the Monitor class to ensure that no other thread is allowed to access a section of application code being executed by the lock owner, unless the other thread is executing the code using a different locked object.

이 문서의 내용In this article:

Monitor 클래스: 개요 The Monitor class: An overview
Lock 개체입니다. The lock object
임계 영역 The critical section
Pulse, System.threading.monitor.pulseall 및 Wait Pulse, PulseAll, and Wait
모니터 및 대기 핸들Monitors and wait handles

Monitor 클래스: 개요The Monitor class: An overview

Monitor에 포함된 기능은 다음과 같습니다.Monitor has the following features:

  • 요청 시 개체와 연결 됩니다.It is associated with an object on demand.

  • 바인딩되지 않습니다. 즉, 모든 컨텍스트에서 직접 호출할 수 있습니다.It is unbound, which means it can be called directly from any context.

  • 클래스의 인스턴스를 Monitor 만들 수 없습니다. 클래스의 메서드는 Monitor 모두 정적입니다.An instance of the Monitor class cannot be created; the methods of the Monitor class are all static. 각 메서드는 임계 영역에 대 한 액세스를 제어 하는 동기화 된 개체를 전달 합니다.Each method is passed the synchronized object that controls access to the critical section.

참고

클래스를 사용 Monitor 하 여 String 값 형식이 아닌 문자열 (이외의 참조 형식) 이외의 개체를 잠급니다.Use the Monitor class to lock objects other than strings (that is, reference types other than String), not value types. 자세한 내용은 Enter 이 문서의 뒷부분에 나오는 메서드의 오버 로드 및 잠금 개체 섹션을 참조 하세요.For details, see the overloads of the Enter method and The lock object section later in this article.

다음 표에서는 동기화 된 개체에 액세스 하는 스레드에서 수행할 수 있는 작업에 대해 설명 합니다.The following table describes the actions that can be taken by threads that access synchronized objects:

작업Action DescriptionDescription
Enter, TryEnterEnter, TryEnter 개체에 대 한 잠금을 가져옵니다.Acquires a lock for an object. 이 작업은 또한 임계 영역 시작을 표시 합니다.This action also marks the beginning of a critical section. 임계 영역에서 다른 잠긴 개체를 사용 하 여 명령을 실행 하는 경우를 제외 하 고는 다른 스레드가 임계 영역을 입력할 수 없습니다.No other thread can enter the critical section unless it is executing the instructions in the critical section using a different locked object.
Wait 다른 스레드가 개체를 잠그고 액세스 하도록 허용 하기 위해 개체에 대 한 잠금을 해제 합니다.Releases the lock on an object in order to permit other threads to lock and access the object. 호출 스레드는 다른 스레드가 개체에 액세스 하는 동안 대기 합니다.The calling thread waits while another thread accesses the object. 펄스 신호는 대기 중인 스레드에 개체의 상태에 대 한 변경 내용을 알리는 데 사용 됩니다.Pulse signals are used to notify waiting threads about changes to an object's state.
Pulse (신호), PulseAllPulse (signal), PulseAll 하나 이상의 대기 중인 스레드에 신호를 보냅니다.Sends a signal to one or more waiting threads. 신호는 대기 중인 스레드에 잠긴 개체의 상태가 변경 되었음을 알리고 잠금 소유자는 잠금을 해제할 준비가 된 것입니다.The signal notifies a waiting thread that the state of the locked object has changed, and the owner of the lock is ready to release the lock. 대기 중인 스레드는 개체에 대 한 잠금을 받을 수 있도록 개체의 준비 된 큐에 배치 됩니다.The waiting thread is placed in the object's ready queue so that it might eventually receive the lock for the object. 스레드에 잠금이 있으면 개체의 새 상태를 확인 하 여 필요한 상태에 도달 했는지 확인할 수 있습니다.Once the thread has the lock, it can check the new state of the object to see if the required state has been reached.
Exit 개체에 대 한 잠금을 해제 합니다.Releases the lock on an object. 이 작업은 또한 잠긴 개체에 의해 보호 되는 임계 영역의 끝을 표시 합니다.This action also marks the end of a critical section protected by the locked object.

부터 .NET Framework 4.NET Framework 4 및 메서드에 대 한 두 개의 오버 로드 집합이 있습니다 Enter TryEnter .Beginning with the .NET Framework 4.NET Framework 4, there are two sets of overloads for the Enter and TryEnter methods. 한 오버 로드 집합에는 잠금을 ref ByRef Boolean true 획득할 때 예외가 throw 되는 경우에도 잠금이 획득 된 경우로 원자 단위로 설정 되는 (c #의 경우) 또는 (Visual Basic) 매개 변수가 있습니다.One set of overloads has a ref (in C#) or ByRef (in Visual Basic) Boolean parameter that is atomically set to true if the lock is acquired, even if an exception is thrown when acquiring the lock. 잠금이 보호 되는 리소스의 상태가 일관 되지 않을 수 있는 경우에도 모든 경우에 잠금을 해제 하는 것이 중요 한 경우에는 이러한 오버 로드를 사용 합니다.Use these overloads if it is critical to release the lock in all cases, even when the resources the lock is protecting might not be in a consistent state.

Lock 개체입니다.The lock object

Monitor 클래스는 static Shared 임계 영역에 대 한 액세스를 제어 하는 개체에서 작동 하는 (c #의 경우) 또는 (Visual Basic) 메서드로 구성 됩니다.The Monitor class consists of static (in C#) or Shared (in Visual Basic) methods that operate on an object that controls access to the critical section. 다음 정보는 동기화 된 각 개체에 대해 유지 관리 됩니다.The following information is maintained for each synchronized object:

  • 현재 잠금을 보유 하는 스레드에 대 한 참조입니다.A reference to the thread that currently holds the lock.

  • 잠금을 가져올 준비가 된 스레드를 포함 하는 준비 된 큐에 대 한 참조입니다.A reference to a ready queue, which contains the threads that are ready to obtain the lock.

  • 잠겨 있는 개체의 상태 변경에 대 한 알림을 대기 중인 스레드를 포함 하는 대기 큐에 대 한 참조입니다.A reference to a waiting queue, which contains the threads that are waiting for notification of a change in the state of the locked object.

Monitor 값 형식이 아닌 개체 (참조 형식)를 잠급니다.Monitor locks objects (that is, reference types), not value types. 값 형식을 및에 전달할 수 있지만 Enter Exit 각 호출에 대해 개별적으로 boxing 됩니다.While you can pass a value type to Enter and Exit, it is boxed separately for each call. 각 호출에서 별도의 개체를 만들기 때문에는 차단 되지 않으며 Enter 보호 하 고 있는 코드는 사실상 동기화 되지 않습니다.Since each call creates a separate object, Enter never blocks, and the code it is supposedly protecting is not really synchronized. 또한에 전달 된 개체가 Exit 에 전달 된 개체와 다르므로 Enter Monitor SynchronizationLockException "개체 동기화 메서드가 동기화 되지 않은 코드 블록에서 호출 되었습니다." 라는 메시지와 함께 예외가 throw 됩니다.In addition, the object passed to Exit is different from the object passed to Enter, so Monitor throws SynchronizationLockException exception with the message "Object synchronization method was called from an unsynchronized block of code."

다음 예제에서는 이 문제를 보여 줍니다.The following example illustrates this problem. 각각 250 밀리초 동안 대기 하는 10 개의 작업을 시작 합니다.It launches ten tasks, each of which just sleeps for 250 milliseconds. 그런 다음 각 태스크는 카운터 변수를 업데이트 nTasks 합니다 .이 변수는 실제로 시작 되 고 실행 된 작업의 수를 계산 하기 위한 것입니다.Each task then updates a counter variable, nTasks, which is intended to count the number of tasks that actually launched and executed. nTasks는 여러 태스크에서 동시에 업데이트할 수 있는 전역 변수 이므로 여러 작업에 의해 동시에 수정 되지 않도록 모니터를 사용 합니다.Because nTasks is a global variable that can be updated by multiple tasks simultaneously, a monitor is used to protect it from simultaneous modification by multiple tasks. 그러나 예제의 출력에 표시 된 것 처럼 각 작업은 예외를 throw SynchronizationLockException 합니다.However, as the output from the example shows, each of the tasks throws a SynchronizationLockException exception.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {

      int nTasks = 0;
      List<Task> tasks = new List<Task>();

      try {
         for (int ctr = 0; ctr < 10; ctr++)
            tasks.Add(Task.Run( () => { // 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);
                                        }
                                      } ));
         Task.WaitAll(tasks.ToArray());
         Console.WriteLine("{0} tasks started and executed.", nTasks);
      }
      catch (AggregateException e) {
         String msg = String.Empty;
         foreach (var ie in e.InnerExceptions) {
            Console.WriteLine("{0}", ie.GetType().Name);
            if (! msg.Contains(ie.Message))
               msg += ie.Message + Environment.NewLine;
         }
         Console.WriteLine("\nException Message(s):");
         Console.WriteLine(msg);
      }
   }
}
// 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.
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.

각 작업 SynchronizationLockException nTasks 에서 메서드를 호출 하기 전에 변수가 boxing 되기 때문에 각 작업에서 예외가 throw 됩니다 Monitor.Enter .Each task throws a SynchronizationLockException exception because the nTasks variable is boxed before the call to the Monitor.Enter method in each task. 즉, 각 메서드 호출에는 서로 독립적인 별도의 변수가 전달 됩니다.In other words, each method call is passed a separate variable that is independent of the others. nTasks 는 메서드 호출에서 다시 boxing 됩니다 Monitor.Exit .nTasks is boxed again in the call to the Monitor.Exit method. 다시 한 번,이는 서로 독립적인 10 개의 새 boxed 변수, nTasks 및 메서드 호출에서 생성 된 boxed 변수 10 개를 만듭니다 Monitor.Enter .Once again, this creates ten new boxed variables, which are independent of each other, nTasks, and the ten boxed variables created in the call to the Monitor.Enter method. 코드가 이전에 잠기지 않은 새로 만든 변수에 대 한 잠금을 해제 하려고 하기 때문에 예외가 throw 됩니다.The exception is thrown, then, because our code is attempting to release a lock on a newly created variable that was not previously locked.

다음 예제와 같이 및를 호출 하기 전에 값 형식 변수를 boxing 하 Enter Exit 고 두 메서드에 동일한 boxed 개체를 전달할 수 있지만이 작업을 수행 하는 것은 장점이 없습니다.Although you can box a value type variable before calling Enter and Exit, as shown in the following example, and pass the same boxed object to both methods, there is no advantage to doing this. Unboxed 변수에 대 한 변경 내용은 boxed 복사본에 반영 되지 않으며, boxed 복사본의 값을 변경할 수 있는 방법이 없습니다.Changes to the unboxed variable are not reflected in the boxed copy, and there is no way to change the value of the boxed copy.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {

      int nTasks = 0;
      object o = nTasks;
      List<Task> tasks = new List<Task>();

      try {
         for (int ctr = 0; ctr < 10; ctr++)
            tasks.Add(Task.Run( () => { // Instead of doing some work, just sleep.
                                        Thread.Sleep(250);
                                        // Increment the number of tasks.
                                        Monitor.Enter(o);
                                        try {
                                           nTasks++;
                                        }
                                        finally {
                                           Monitor.Exit(o);
                                        }
                                      } ));
         Task.WaitAll(tasks.ToArray());
         Console.WriteLine("{0} tasks started and executed.", nTasks);
      }
      catch (AggregateException e) {
         String msg = String.Empty;
         foreach (var ie in e.InnerExceptions) {
            Console.WriteLine("{0}", ie.GetType().Name);
            if (! msg.Contains(ie.Message))
               msg += ie.Message + Environment.NewLine;
         }
         Console.WriteLine("\nException Message(s):");
         Console.WriteLine(msg);
      }
   }
}
// The example displays the following output:
//        10 tasks started and executed.
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.

동기화 할 개체를 선택할 때 전용 또는 내부 개체만 잠가야 합니다.When selecting an object on which to synchronize, you should lock only on private or internal objects. 외부 개체를 잠그면 관련이 없는 코드에서 다른 용도로 잠글 동일한 개체를 선택할 수 있기 때문에 교착 상태가 발생할 수 있습니다.Locking on external objects might result in deadlocks, because unrelated code could choose the same objects to lock on for different purposes.

잠금에 사용 되는 개체에서 파생 되는 경우 여러 애플리케이션 도메인의 개체에 동기화 할 수 있는 참고 MarshalByRefObject합니다.Note that you can synchronize on an object in multiple application domains if the object used for the lock derives from MarshalByRefObject.

임계 영역The critical section

Enter및 메서드를 사용 Exit 하 여 임계 영역의 시작과 끝을 표시 합니다.Use the Enter and Exit methods to mark the beginning and end of a critical section.

참고

및 메서드에서 제공 하는 Enter 기능은 Exit c #의 lock 문에 의해 제공 된 기능과 동일 합니다. 단, 언어 구문에서 SyncLock Monitor.Enter(Object, Boolean) 메서드 오버 로드와 메서드를 래핑하는 경우를 제외 하 고는 Visual Basic의 SyncLock 문입니다 Monitor.Exit . try``finallyThe functionality provided by the Enter and Exit methods is identical to that provided by the lock statement in C# and the SyncLock statement in Visual Basic, except that the language constructs wrap the Monitor.Enter(Object, Boolean) method overload and the Monitor.Exit method in a tryfinally 모니터를 해제 하 여 모니터를 해제 합니다.block to ensure that the monitor is released.

임계 섹션이 연속 된 명령 집합인 경우 메서드에서 획득 한 잠금은 Enter 단일 스레드만 잠긴 개체를 사용 하 여 포함 된 코드를 실행할 수 있도록 보장 합니다.If the critical section is a set of contiguous instructions, then the lock acquired by the Enter method guarantees that only a single thread can execute the enclosed code with the locked object. 이 경우 블록에 해당 코드를 저장 하 tryExit 블록에 메서드에 대 한 호출을 추가 하는 것이 좋습니다 finally .In this case, we recommend that you place that code in a try block and place the call to the Exit method in a finally block. 이렇게 하면 예외가 발생 해도 잠금이 해제 됩니다.This ensures that the lock is released even if an exception occurs. 다음 코드 조각에서는이 패턴을 보여 줍니다.The following code fragment illustrates this pattern.

// Define the lock object.
var obj = 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);
}
' 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

이 기능은 일반적으로 클래스의 정적 또는 인스턴스 메서드에 대 한 액세스를 동기화 하는 데 사용 됩니다.This facility is typically used to synchronize access to a static or instance method of a class.

중요 한 섹션이 전체 메서드에 걸쳐 있는 경우를 메서드에 배치 하 System.Runtime.CompilerServices.MethodImplAttributeSynchronized 의 생성자에 값을 지정 하 여 잠금 기능을 구현할 수 있습니다 System.Runtime.CompilerServices.MethodImplAttribute .If a critical section spans an entire method, the locking facility can be achieved by placing the System.Runtime.CompilerServices.MethodImplAttribute on the method, and specifying the Synchronized value in the constructor of System.Runtime.CompilerServices.MethodImplAttribute. 이 특성을 사용 하는 경우 EnterExit 메서드 호출은 필요 하지 않습니다.When you use this attribute, the Enter and Exit method calls are not needed. 다음 코드 조각에서는이 패턴을 보여 줍니다.The following code fragment illustrates this pattern:

[MethodImplAttribute(MethodImplOptions.Synchronized)]
void MethodToLock()
{
   // Method implementation.
} 
<MethodImplAttribute(MethodImplOptions.Synchronized)>
Sub MethodToLock()
   ' Method implementation.
End Sub 

특성은 메서드가 반환 될 때까지 현재 스레드가 잠금을 보유 하도록 합니다. 잠금을 빨리 해제할 수 있는 경우에는 Monitor 클래스, c # lock 문 또는 특성 대신 메서드 내의 Visual Basic SyncLock 문을 사용 합니다.Note that the attribute causes the current thread to hold the lock until the method returns; if the lock can be released sooner, use the Monitor class, the C# lock statement, or the Visual Basic SyncLock statement inside of the method instead of the attribute.

Enter Exit 지정 된 개체를 잠금 및 해제 하는 및 문에서는 멤버 또는 클래스 경계를 교차 하거나 둘 다를 수행할 수 있지만이 방법은 권장 되지 않습니다.While it is possible for the Enter and Exit statements that lock and release a given object to cross member or class boundaries or both, this practice is not recommended.

Pulse, System.threading.monitor.pulseall 및 WaitPulse, PulseAll, and Wait

스레드가 잠금을 소유 하 고 잠금이 보호 하는 임계 영역을 입력 한 후에는 Monitor.Wait , 및 메서드를 호출할 수 있습니다 Monitor.Pulse Monitor.PulseAll .Once a thread owns the lock and has entered the critical section that the lock protects, it can call the Monitor.Wait, Monitor.Pulse, and Monitor.PulseAll methods.

잠금을 보유 하는 스레드가 호출 되 면 Wait 잠금이 해제 되 고 스레드가 동기화 된 개체의 대기 큐에 추가 됩니다.When the thread that holds the lock calls Wait, the lock is released and the thread is added to the waiting queue of the synchronized object. 준비 된 큐의 첫 번째 스레드 (있는 경우)는 잠금을 획득 하 고 임계 영역에 들어갑니다.The first thread in the ready queue, if any, acquires the lock and enters the critical section. 를 호출 하는 스레드는 Wait Monitor.Pulse Monitor.PulseAll 잠금을 보유 하는 스레드 (이동 하기 위해 스레드가 대기 큐의 맨 위에 있어야 함)에서 또는 메서드를 호출할 때 대기 큐에서 준비 된 큐로 이동 합니다.The thread that called Wait is moved from the waiting queue to the ready queue when either the Monitor.Pulse or the Monitor.PulseAll method is called by the thread that holds the lock (to be moved, the thread must be at the head of the waiting queue). Wait메서드는 호출 스레드가 잠금을 다시 가져옵니다 때를 반환 합니다.The Wait method returns when the calling thread reacquires the lock.

잠금을 보유 하는 스레드가 호출 되 면 Pulse 대기 중인 큐의 헤드에 있는 스레드가 준비 된 큐로 이동 합니다.When the thread that holds the lock calls Pulse, the thread at the head of the waiting queue is moved to the ready queue. 메서드를 호출 하면 PulseAll 대기 중인 큐의 모든 스레드가 준비 된 큐로 이동 합니다.The call to the PulseAll method moves all the threads from the waiting queue to the ready queue.

모니터 및 대기 핸들Monitors and wait handles

클래스와 개체를 사용 하는 것의 차이를 확인 하는 것이 중요 합니다 Monitor WaitHandle .It is important to note the distinction between the use of the Monitor class and WaitHandle objects.

  • Monitor클래스는 전적으로 관리 되 고 완전히 이식 가능 하며 운영 체제 리소스 요구 사항 측면에서 더 효율적일 수 있습니다.The Monitor class is purely managed, fully portable, and might be more efficient in terms of operating-system resource requirements.

  • WaitHandle 개체는 운영 체제 대기 가능 개체를 나타내며, 관리 코드와 비관리 코드 간의 동기화에 유용 하며, 여러 개체를 한 번에 대기 하는 기능과 같은 일부 고급 운영 체제 기능을 노출 합니다.WaitHandle objects represent operating-system waitable objects, are useful for synchronizing between managed and unmanaged code, and expose some advanced operating-system features like the ability to wait on many objects at once.

속성

LockContentionCount

모니터의 잠금을 시도할 때 경합이 발생한 횟수를 가져옵니다.Gets the number of times there was contention when trying to take the monitor's lock.

메서드

Enter(Object)

지정된 개체의 단독 잠금을 가져옵니다.Acquires an exclusive lock on the specified object.

Enter(Object, Boolean)

지정된 개체의 단독 잠금을 가져오고 잠금 설정 여부를 나타내는 값을 자동으로 설정합니다.Acquires an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.

Exit(Object)

지정된 개체의 단독 잠금을 해제합니다.Releases an exclusive lock on the specified object.

IsEntered(Object)

현재 스레드가 지정된 개체에 대한 잠금을 보유하는지 여부를 확인합니다.Determines whether the current thread holds the lock on the specified object.

Pulse(Object)

대기 중인 큐에 포함된 스레드에 잠겨 있는 개체의 상태 변경을 알립니다.Notifies a thread in the waiting queue of a change in the locked object's state.

PulseAll(Object)

대기 중인 모든 스레드에 개체 상태 변경을 알립니다.Notifies all waiting threads of a change in the object's state.

TryEnter(Object)

지정된 개체의 단독 잠금을 가져오려고 했습니다.Attempts to acquire an exclusive lock on the specified object.

TryEnter(Object, Boolean)

지정된 개체의 단독 잠금을 가져오고 잠금 설정 여부를 나타내는 값을 자동으로 설정하려고 시도합니다.Attempts to acquire an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.

TryEnter(Object, Int32)

지정된 시간(밀리초) 동안 지정된 개체의 단독 잠금을 가져오려고 했습니다.Attempts, for the specified number of milliseconds, to acquire an exclusive lock on the specified object.

TryEnter(Object, Int32, Boolean)

지정된 시간(밀리초) 동안 지정된 개체의 단독 잠금을 가져오고 잠금 설정 여부를 나타내는 값을 자동으로 설정하려고 시도합니다.Attempts, for the specified number of milliseconds, to acquire an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.

TryEnter(Object, TimeSpan)

지정된 시간 동안 지정된 개체의 단독 잠금을 가져오려고 했습니다.Attempts, for the specified amount of time, to acquire an exclusive lock on the specified object.

TryEnter(Object, TimeSpan, Boolean)

지정된 시간 동안 지정된 개체의 단독 잠금을 가져오고 잠금 설정 여부를 나타내는 값을 자동으로 설정하려고 시도합니다.Attempts, for the specified amount of time, to acquire an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.

Wait(Object)

개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단합니다.Releases the lock on an object and blocks the current thread until it reacquires the lock.

Wait(Object, Int32)

개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단합니다.Releases the lock on an object and blocks the current thread until it reacquires the lock. 지정된 시간 제한 간격이 지나면 스레드가 준비된 큐에 들어갑니다.If the specified time-out interval elapses, the thread enters the ready queue.

Wait(Object, Int32, Boolean)

개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단합니다.Releases the lock on an object and blocks the current thread until it reacquires the lock. 지정된 시간 제한 간격이 지나면 스레드가 준비된 큐에 들어갑니다.If the specified time-out interval elapses, the thread enters the ready queue. 또한 이 메서드는 컨텍스트의 동기화 도메인(동기화된 컨텍스트에 있는 경우)을 대기 전에 종료하고 나중에 다시 가져오는지 여부도 지정합니다.This method also specifies whether the synchronization domain for the context (if in a synchronized context) is exited before the wait and reacquired afterward.

Wait(Object, TimeSpan)

개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단합니다.Releases the lock on an object and blocks the current thread until it reacquires the lock. 지정된 시간 제한 간격이 지나면 스레드가 준비된 큐에 들어갑니다.If the specified time-out interval elapses, the thread enters the ready queue.

Wait(Object, TimeSpan, Boolean)

개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단합니다.Releases the lock on an object and blocks the current thread until it reacquires the lock. 지정된 시간 제한 간격이 지나면 스레드가 준비된 큐에 들어갑니다.If the specified time-out interval elapses, the thread enters the ready queue. 필요에 따라 동기화된 컨텍스트의 동기화 도메인을 대기 전에 종료하고 나중에 해당 도메인을 다시 가져옵니다.Optionally exits the synchronization domain for the synchronized context before the wait and reacquires the domain afterward.

적용 대상

스레드 보안

이 형식은 스레드로부터 안전합니다.This type is thread safe.

추가 정보