Общие сведения о примитивах синхронизацииOverview of synchronization primitives

Платформа .NET предоставляет ряд типов для синхронизации доступа к общему ресурсу или координации взаимодействия потоков..NET provides a range of types that you can use to synchronize access to a shared resource or coordinate thread interaction.

Важно!

С помощью одного экземпляра примитива синхронизации можно обеспечить защиту при обращении к общему ресурсу.Use the same synchronization primitive instance to protect access of a shared resource. Если для защиты одного и того же ресурса используются разные экземпляры примитива синхронизации, то защита, предоставляемая примитивом синхронизации, будет обходиться.If you use different synchronization primitive instances to protect the same resource, you'll circumvent the protection provided by a synchronization primitive.

Класс WaitHandle и типы упрощенной синхронизацииWaitHandle class and lightweight synchronization types

Несколько примитивов синхронизации .NET являются производными от класса System.Threading.WaitHandle, который инкапсулирует собственный дескриптор операционной системы синхронизации и использует механизм сигнализации для взаимодействия потоков.Multiple .NET synchronization primitives derive from the System.Threading.WaitHandle class, which encapsulates a native operating system synchronization handle and uses a signaling mechanism for thread interaction. К ним относятся такие классы:Those classes include:

  • System.Threading.Mutex, который предоставляет монопольный доступ к общему ресурсу.System.Threading.Mutex, which grants exclusive access to a shared resource. Если мьютексом не владеет ни один поток, сообщается состояние мьютекса.The state of a mutex is signaled if no thread owns it.
  • System.Threading.Semaphore, ограничивающий число потоков, которые могут одновременно обращаться к ресурсу или пулу ресурсов.System.Threading.Semaphore, which limits the number of threads that can access a shared resource or a pool of resources concurrently. Состояние семафора становится сигнальным, когда это число становится больше нуля, и несигнальным, когда равно нулю.The state of a semaphore is set to signaled when its count is greater than zero, and nonsignaled when its count is zero.
  • System.Threading.EventWaitHandle, который представляет событие синхронизации потоков и может быть в сигнальном или несигнальном состоянии.System.Threading.EventWaitHandle, which represents a thread synchronization event and can be either in a signaled or unsignaled state.
  • System.Threading.AutoResetEvent, который является производным от EventWaitHandle и при получении сигнала автоматически сбрасывается в сигнальное состояние после освобождения одиночного потока в состоянии ожидания.System.Threading.AutoResetEvent, which derives from EventWaitHandle and, when signaled, resets automatically to an unsignaled state after releasing a single waiting thread.
  • System.Threading.ManualResetEvent, который является производным от EventWaitHandle и при получении сигнала остается в сигнальном состоянии до вызова метода Reset.System.Threading.ManualResetEvent, which derives from EventWaitHandle and, when signaled, stays in a signaled state until the Reset method is called.

Так как WaitHandle наследует System.MarshalByRefObject, в .NET Framework эти типы можно использовать для синхронизации действий потоков за пределами доменов приложений.In the .NET Framework, because WaitHandle derives from System.MarshalByRefObject, these types can be used to synchronize the activities of threads across application domain boundaries.

В .NET Framework и .NET Core некоторые из этих типов могут быть именованными дескрипторами синхронизации системы, которые видны в операционной системе и могут использоваться для синхронизации между процессами:In the .NET Framework and .NET Core, some of these types can represent named system synchronization handles, which are visible throughout the operating system and can be used for the inter-process synchronization:

  • Mutex (.NET Framework и .NET Core);Mutex (.NET Framework and .NET Core),
  • Semaphore (.NET Framework и .NET Core в Windows);Semaphore (.NET Framework and .NET Core on Windows),
  • EventWaitHandle (.NET Framework и .NET Core в Windows).EventWaitHandle (.NET Framework and .NET Core on Windows).

Дополнительные сведения см. в справочной документации по API WaitHandle.For more information, see the WaitHandle API reference.

Типы упрощенной синхронизации не основаны на дескрипторах базовой операционной системы и обычно обеспечивают лучшее быстродействие.Lightweight synchronization types don't rely on underlying operating system handles and typically provide better performance. Тем не менее они не могут использоваться для внутрипроцессной синхронизации.However, they cannot be used for the inter-process synchronization. Эти типы можно использовать для синхронизации потоков в одном приложении.Use those types for thread synchronization within one application.

Некоторые из них являются альтернативой типам, производным от WaitHandle.Some of those types are alternatives to the types derived from WaitHandle. Например, SemaphoreSlim является упрощенной альтернативой Semaphore.For example, SemaphoreSlim is a lightweight alternative to Semaphore.

Синхронизация доступа к общему ресурсуSynchronization of access to a shared resource

Платформа .NET предоставляет ряд примитивов синхронизации для управления доступом нескольких потоков к общему ресурсу..NET provides a range of synchronization primitives to control access to a shared resource by multiple threads.

Monitor - классMonitor class

Класс System.Threading.Monitor предоставляет монопольный доступ к общему ресурсу, блокируя или разблокируя объект, определяющий ресурс.The System.Threading.Monitor class grants mutually exclusive access to a shared resource by acquiring or releasing a lock on the object that identifies the resource. Во время блокировки поток, удерживающий блокировку, может снова поставить и снять блокировку.While a lock is held, the thread that holds the lock can again acquire and release the lock. Любой другой поток не может получить блокировку, и метод Monitor.Enter ожидает снятия блокировки.Any other thread is blocked from acquiring the lock and the Monitor.Enter method waits until the lock is released. Метод Enter получает снятую блокировку.The Enter method acquires a released lock. Можно также использовать метод Monitor.TryEnter, чтобы задать количество времени, в течение которого поток пытается получить блокировку.You can also use the Monitor.TryEnter method to specify the amount of time during which a thread attempts to acquire a lock. Так как класс Monitor реализует привязку потока, поток, который получил блокировку, должен снять ее, вызвав метод Monitor.Exit.Because the Monitor class has thread affinity, the thread that acquired a lock must release the lock by calling the Monitor.Exit method.

Можно координировать взаимодействие потоков, которые получают блокировку для одного и того же объекта, с помощью методов Monitor.Wait, Monitor.Pulse и Monitor.PulseAll.You can coordinate the interaction of threads that acquire a lock on the same object by using the Monitor.Wait, Monitor.Pulse, and Monitor.PulseAll methods.

Дополнительные сведения см. в справочной документации по API Monitor.For more information, see the Monitor API reference.

Примечание

С помощью операторов lock в C# и SyncLock в Visual Basic можно синхронизировать доступ к общему ресурсу вместо использования класса Monitor напрямую.Use the lock statement in C# and the SyncLock statement in Visual Basic to synchronize access to a shared resource instead of using the Monitor class directly. Эти операторы реализуются с помощью методов Enter, Exit и блока try…finally, обеспечивающих постоянное снятие полученной блокировки.Those statements are implemented by using the Enter and Exit methods and a try…finally block to ensure that the acquired lock is always released.

Mutex - классMutex class

Как и System.Threading.Mutex, класс Monitor предоставляет монопольный доступ к общему ресурсу.The System.Threading.Mutex class, like Monitor, grants exclusive access to a shared resource. С помощью вызова одной из перегрузок метода Mutex.WaitOne можно запросить владение мьютексом.Use one of the Mutex.WaitOne method overloads to request the ownership of a mutex. Как и Monitor, Mutex реализует привязку потока и поток, который получил мьютекс, должен освободить его, вызвав метод Mutex.ReleaseMutex.Like Monitor, Mutex has thread affinity and the thread that acquired a mutex must release it by calling the Mutex.ReleaseMutex method.

В отличие от Monitor, класс Mutex может использоваться для внутрипроцессной синхронизации.Unlike Monitor, the Mutex class can be used for inter-process synchronization. Для этого нужно использовать именованный мьютекс, который виден в операционной системе.To do that, use a named mutex, which is visible throughout the operating system. Чтобы создать экземпляр именованного мьютекса, используйте конструктор Mutex, который задает имя.To create a named mutex instance, use a Mutex constructor that specifies a name. Также можно вызвать метод Mutex.OpenExisting, чтобы открыть существующий именованный системный мьютекс.You also can call the Mutex.OpenExisting method to open an existing named system mutex.

Дополнительные сведения см. в статье о мьютексах и справочной документации по API Mutex.For more information, see the Mutexes article and the Mutex API reference.

Структура SpinLockSpinLock structure

Структура System.Threading.SpinLock, например Monitor, предоставляет монопольный доступ к общему ресурсу на основе доступности блокировки.The System.Threading.SpinLock structure, like Monitor, grants exclusive access to a shared resource based on the availability of a lock. Когда SpinLock пытается получить блокировку, которая недоступна, этот примитив будет ожидать в цикле, постоянно проверяя возможность получения блокировки.When SpinLock attempts to acquire a lock that is unavailable, it waits in a loop, repeatedly checking until the lock becomes available.

Дополнительные сведения о преимуществах и недостатках использования SpinLock см. в статье о SpinLock и справочной документации по API SpinLock.For more information about the benefits and drawbacks of using spin lock, see the SpinLock article and the SpinLock API reference.

Класс ReaderWriterLockSlimReaderWriterLockSlim class

Класс System.Threading.ReaderWriterLockSlim предоставляет монопольный доступ к общему ресурсу для записи и обеспечивает одновременный доступ к ресурсу для чтения нескольким потокам.The System.Threading.ReaderWriterLockSlim class grants exclusive access to a shared resource for writing and allows multiple threads to access the resource simultaneously for reading. Можно использовать ReaderWriterLockSlim для синхронизации доступа к общей структуре данных, поддерживающей потокобезопасные операции чтения, но требующей монопольного доступа для выполнения операции записи.You might want to use ReaderWriterLockSlim to synchronize access to a shared data structure that supports thread-safe read operations, but requires exclusive access to perform write operation. Если поток запрашивает монопольный доступ (например, путем вызова метода ReaderWriterLockSlim.EnterWriteLock), последующие запросы модуля чтения и записи блокируются, пока все существующие модули чтения не освободят блокировку, а модуль записи не получит и не снимет блокировку.When a thread requests exclusive access (for example, by calling the ReaderWriterLockSlim.EnterWriteLock method), subsequent reader and writer requests block until all existing readers have exited the lock, and the writer has entered and exited the lock.

Дополнительные сведения см. в справочной документации по API ReaderWriterLockSlim.For more information, see the ReaderWriterLockSlim API reference.

Классы Semaphore и SemaphoreSlimSemaphore and SemaphoreSlim classes

Классы System.Threading.Semaphore и System.Threading.SemaphoreSlim ограничивают число потоков, которые могут одновременно обращаться к ресурсу или пулу ресурсов.The System.Threading.Semaphore and System.Threading.SemaphoreSlim classes limit the number of threads that can access a shared resource or a pool of resources concurrently. Дополнительные потоки, запрашивающие ресурс, ожидают освобождения семафора любым из потоков.Additional threads that request the resource wait until any thread releases the semaphore. Так как семафор не реализует привязку потока, поток может занять семафор, а другой поток может его освободить.Because the semaphore doesn't have thread affinity, a thread can acquire the semaphore and another one can release it.

SemaphoreSlim — это упрощенная альтернативаSemaphore, которую можно использовать для синхронизации в рамках одного процесса.SemaphoreSlim is a lightweight alternative to Semaphore and can be used only for synchronization within a single process boundary.

В Windows можно использовать Semaphore для внутрипроцессной синхронизации.On Windows, you can use Semaphore for the inter-process synchronization. Для этого необходимо создать экземпляр Semaphore, выполняющий роль именованного системного семафора. Это можно сделать с помощью конструкторов Semaphore, которые задают имя или метод Semaphore.OpenExisting.To do that, create a Semaphore instance that represents a named system semaphore by using one of the Semaphore constructors that specifies a name or the Semaphore.OpenExisting method. SemaphoreSlim не поддерживает именованные системные семафоры.SemaphoreSlim doesn't support named system semaphores.

Дополнительные сведения см. в статье о классах Semaphore и SemaphoreSlim и справочной документации по API Semaphore или SemaphoreSlim.For more information, see the Semaphore and SemaphoreSlim article and the Semaphore or SemaphoreSlim API reference.

Взаимодействие потоков или сигнализацияThread interaction, or signaling

Взаимодействие потоков (или сигнализация потоков) означает, что поток должен ждать уведомления или сигнала от одного или нескольких потоков, чтобы продолжить.Thread interaction (or thread signaling) means that a thread must wait for notification, or a signal, from one or more threads in order to proceed. Например, если поток A вызывает метод Thread.Join потока B, поток А блокируется до завершения потока B.For example, if thread A calls the Thread.Join method of thread B, thread A is blocked until thread B completes. Примитивы синхронизации, описанные в предыдущем разделе, реализуют другой механизм сигнализации: снятие блокировки потоком является сигналом другому потоку о возможности продолжать исполнение, получив блокировку.The synchronization primitives described in the preceding section provide a different mechanism for signaling: by releasing a lock, a thread notifies another thread that it can proceed by acquiring the lock.

В этом разделе описываются дополнительные сигнальные конструкции, предоставляемые .NET.This section describes additional signaling constructs provided by .NET.

Классы EventWaitHandle, AutoResetEvent и ManualResetEventEventWaitHandle, AutoResetEvent, ManualResetEvent, and ManualResetEventSlim classes

Класс System.Threading.EventWaitHandle представляет событие синхронизации потока.The System.Threading.EventWaitHandle class represents a thread synchronization event.

Событие синхронизации может находиться в сигнальном или несигнальном состоянии.A synchronization event can be either in an unsignaled or signaled state. Если состояние события несигнальное, поток, который вызывает перегрузку события WaitOne, будет заблокирован, пока состояние события не станет сигнальным.When the state of an event is unsignaled, a thread that calls the event's WaitOne overload is blocked until an event is signaled. Метод EventWaitHandle.Set задает сигнальное состояние события.The EventWaitHandle.Set method sets the state of an event to signaled.

Поведение EventWaitHandle после получения сигнала зависит от его режима сброса:The behavior of an EventWaitHandle that has been signaled depends on its reset mode:

В Windows можно использовать EventWaitHandle для синхронизации между процессами.On Windows, you can use EventWaitHandle for the inter-process synchronization. Для этого необходимо создать экземпляр EventWaitHandle, выполняющий роль именованного системного события синхронизации. Это можно сделать с помощью конструкторов EventWaitHandle, которые задают имя или метод EventWaitHandle.OpenExisting.To do that, create a EventWaitHandle instance that represents a named system synchronization event by using one of the EventWaitHandle constructors that specifies a name or the EventWaitHandle.OpenExisting method.

Дополнительные сведения см. в статье о EventWaitHandle.For more information, see the EventWaitHandle article. Справочные сведения об API см. здесь: EventWaitHandle, AutoResetEvent, ManualResetEvent и ManualResetEventSlim.For the API reference, see EventWaitHandle, AutoResetEvent, ManualResetEvent, and ManualResetEventSlim.

Класс CountdownEventCountdownEvent class

Класс System.Threading.CountdownEvent представляет событие, возникающее, когда его счетчик имеет значение ноль.The System.Threading.CountdownEvent class represents an event that becomes set when its count is zero. Когда CountdownEvent.CurrentCount не равен нулю, поток, который вызывает CountdownEvent.Wait, блокируется.While CountdownEvent.CurrentCount is greater than zero, a thread that calls CountdownEvent.Wait is blocked. Вызовите CountdownEvent.Signal, чтобы уменьшить значение счетчика события.Call CountdownEvent.Signal to decrement an event's count.

В отличие от ManualResetEvent или ManualResetEventSlim, которые позволяют разблокировать несколько потоков с помощью сигнала от одного потока, CountdownEvent может разблокировать один или несколько потоков с помощью сигналов от нескольких потоков.In contrast to ManualResetEvent or ManualResetEventSlim, which you can use to unblock multiple threads with a signal from one thread, you can use CountdownEvent to unblock one or more threads with signals from multiple threads.

Дополнительные сведения см. в статье о CountdownEvent и справочной документации по API CountdownEvent.For more information, see the CountdownEvent article and the CountdownEvent API reference.

Класс BarrierBarrier class

Класс System.Threading.Barrier представляет барьер выполнения потоков.The System.Threading.Barrier class represents a thread execution barrier. Поток, который вызывает метод Barrier.SignalAndWait, сообщает, что он достиг барьера и ожидает, пока другие участвующие потоки не достигнут барьера.A thread that calls the Barrier.SignalAndWait method signals that it reached the barrier and waits until other participant threads reach the barrier. Когда все участвующие потоки достигают барьера, их выполнение продолжается, а барьер сбрасывается и может использоваться повторно.When all participant threads reach the barrier, they proceed and the barrier is reset and can be used again.

Можно использовать Barrier, если одному или нескольким потокам требуются результаты других потоков для перехода к следующему этапу вычисления.You might use Barrier when one or more threads require the results of other threads before proceeding to the next computation phase.

Дополнительные сведения см. в статье о Barrier и справочной документации по API Barrier.For more information, see the Barrier article and the Barrier API reference.

Interlocked - классInterlocked class

Класс System.Threading.Interlocked предоставляет статические методы, которые выполняют простые атомарные операции над переменной.The System.Threading.Interlocked class provides static methods that perform simple atomic operations on a variable. К этим атомарным операциям относится добавление, инкремент и декремент, обмен и условный обмен, зависящий от сравнения, а также операция чтения 64-разрядного целого числа.Those atomic operations include addition, increment and decrement, exchange and conditional exchange that depends on a comparison, and read operation of a 64-bit integer value.

Дополнительные сведения см. в справочной документации по API Interlocked.For more information, see the Interlocked API reference.

Структура SpinWaitSpinWait structure

Структура System.Threading.SpinWait обеспечивает поддержку ожидания спин-блокировки.The System.Threading.SpinWait structure provides support for spin-based waiting. Ее можно использовать, когда потоку нужно дождаться возникновения события или выполнения условия, но фактическое время ожидания будет меньше периода, требуемого для применения дескриптора ожидания или других способов блокировки потока.You might want to use it when a thread has to wait for an event to be signaled or a condition to be met, but when the actual wait time is expected to be less than the waiting time required by using a wait handle or by otherwise blocking the thread. Используя SpinWait, можно задать короткий интервал времени для цикла ожидания, а затем вернуть управление (например, с помощью ожидания или спящего режима), только если условие не было выполнено в течение заданного времени.By using SpinWait, you can specify a short period of time to spin while waiting, and then yield (for example, by waiting or sleeping) only if the condition was not met in the specified time.

Дополнительные сведения см. в статье о SpinWait и справочной документации по API SpinWait.For more information, see the SpinWait article and the SpinWait API reference.

См. такжеSee also