Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
.NET предоставляет ряд типов, которые можно использовать для синхронизации доступа к общему ресурсу или координации взаимодействия потока.
Это важно
Используйте тот же примитивный экземпляр синхронизации для защиты доступа к общему ресурсу. При использовании разных экземпляров примитивов синхронизации для защиты одного ресурса вы будете обойти защиту, предоставляемую примитивом синхронизации.
Класс WaitHandle и упрощенные типы синхронизации
Несколько примитивов синхронизации .NET наследуются от System.Threading.WaitHandle класса, который инкапсулирует собственный дескриптор синхронизации операционной системы и использует механизм сигнализации для взаимодействия потоков. К этим классам относятся:
- System.Threading.Mutex, который предоставляет монопольный доступ к общему ресурсу. Состояние мьютекса сигнализируется, если ни один поток не владеет им.
- System.Threading.Semaphore— это ограничивает количество потоков, которые могут получить доступ к общему ресурсу или пулу ресурсов одновременно. Состояние семафора задается для сигнала, когда его число больше нуля, и незначен, если его число равно нулю.
- System.Threading.EventWaitHandle, представляющий событие синхронизации потоков и может находиться в сигнальном или несигнальном состоянии.
- System.Threading.AutoResetEvent, производный от EventWaitHandle, и при сигнале автоматически сбрасывается в несигнализируемое состояние после освобождения одного ожидающего потока.
- System.Threading.ManualResetEvent, который является производным от EventWaitHandle и, при подаче сигнала, остаётся в сигнальном состоянии до тех пор, пока не будет вызван метод Reset.
В .NET Framework, поскольку WaitHandle является производным от System.MarshalByRefObject, эти типы можно использовать для синхронизации действий потоков между границами домена приложения.
В .NET Framework, .NET Core и .NET 5+ некоторые из этих типов могут представлять именованные ручки синхронизации системы, которые видны во всей операционной системе и могут использоваться для межпроцессной синхронизации.
- Mutex
- Semaphore (в Windows)
- EventWaitHandle (в Windows)
Для получения дополнительной информации см. справочник API WaitHandle.
Упрощенные типы синхронизации не зависят от базовых дескрипторов операционной системы и обычно обеспечивают лучшую производительность. Однако их нельзя использовать для межпроцессной синхронизации. Используйте эти типы для синхронизации потоков в одном приложении.
Некоторые из этих типов являются альтернативами типам, производным от WaitHandle. Например, SemaphoreSlim это упрощенная альтернатива Semaphore.
Синхронизация доступа к общему ресурсу
.NET предоставляет диапазон примитивов синхронизации для управления доступом к общему ресурсу несколькими потоками.
Мониторинг класса
Класс System.Threading.Monitor предоставляет взаимоисключающий доступ к общему ресурсу путем получения или освобождения блокировки объекта, определяющего ресурс. Хотя блокировка удерживается, поток, содержащий блокировку, может снова получить и освободить блокировку. Любой другой поток заблокирован от получения блокировки, и Monitor.Enter метод ожидает, пока блокировка не будет освобождена. Метод Enter получает освобожденную блокировку. Вы также можете использовать метод Monitor.TryEnter для указания времени, в течение которого поток пытается получить блокировку. Поскольку класс Monitor имеет потоковую привязку, поток, который захватил блокировку, должен освободить эту блокировку, вызвав метод Monitor.Exit.
Взаимодействие потоков, получающих блокировку одного объекта, можно координировать с помощью методов Monitor.Wait, Monitor.Pulse и Monitor.PulseAll.
Для получения дополнительной информации см. справочник API Monitor.
Замечание
Используйте инструкцию блокировки в C# и инструкцию SyncLock в Visual Basic, чтобы синхронизировать доступ к общему ресурсу, а не напрямую использовать Monitor класс. Эти операторы реализуются с помощью методов Enter и Exit, а также блока try…finally
, чтобы гарантировать, что приобретённый замок всегда освобождается.
Класс Mutex
Класс System.Threading.Mutex , например Monitor, предоставляет монопольный доступ к общему ресурсу. Используйте одну из перегрузок метода Mutex.WaitOne , чтобы запросить владение мьютексом. Например, Monitor, Mutex имеет привязку потока, и поток, заполучивший мьютекс, должен освободить его, вызвав метод Mutex.ReleaseMutex.
В отличие от Monitor, класс Mutex можно использовать для межпроцессной синхронизации. Для этого используйте именованный мьютекс, который отображается во всей операционной системе. Чтобы создать именованный экземпляр мьютекса, используйте конструктор Mutex , указывающий имя. Можно также вызвать метод Mutex.OpenExisting для открытия существующего системного именованного мьютекса.
Дополнительные сведения см. в статье о Мьютексах и справочнике Mutex по API.
Структура SpinLock
Структура System.Threading.SpinLock, как и Monitor, предоставляет исключительный доступ к общему ресурсу на основе наличия блокировки. Когда SpinLock пытается повторно получить недоступный замок, он ожидает в цикле, снова и снова проверяя доступность до тех пор, пока замок не освободится.
Дополнительные сведения о преимуществах и недостатках использования spin lock см. в статье SpinLock и в справочнике SpinLock по API.
Класс ReaderWriterLockSlim
Класс System.Threading.ReaderWriterLockSlim предоставляет монопольный доступ к общему ресурсу для записи и позволяет нескольким потокам одновременно получать доступ к ресурсу для чтения. Может потребоваться использовать ReaderWriterLockSlim для синхронизации доступа к общей структуре данных, которая поддерживает операции чтения, безопасные для потоков, но требуется монопольный доступ для выполнения операции записи. Когда поток запрашивает исключительный доступ (например, вызывая ReaderWriterLockSlim.EnterWriteLock метод), последующие запросы чтения и записи блокируются, пока все существующие читатели не завершат блокировку, а записывающий поток не войдет и не выйдет из блокировки.
Для получения дополнительной информации см. справочник API ReaderWriterLockSlim.
Классы Semaphore и SemaphoreSlim
Классы System.Threading.Semaphore и System.Threading.SemaphoreSlim ограничивают количество потоков, которые могут получить доступ к общему ресурсу или пулу ресурсов одновременно. Дополнительные потоки, запрашивающие ресурс, ожидают, пока какой-либо поток не освободит семафор. Поскольку семафор не имеет привязки к потокам, один поток может получить семафор, а другой может его освободить.
SemaphoreSlim является упрощенной альтернативой Semaphore и может использоваться только для синхронизации в пределах одной границы процесса.
В Windows можно использовать Semaphore для межпроцессной синхронизации. Для этого создайте экземпляр Semaphore, представляющий именованный системный семафор, используя один из конструкторов Семафора, который задает имя, или метод Semaphore.OpenExisting. SemaphoreSlim не поддерживает именованные системные семафоры.
Дополнительные сведения см. в статье Semaphore и SemaphoreSlim или справочнике по API Semaphore или SemaphoreSlim.
Взаимодействие потоков или межпотоковое сигнализирование
Взаимодействие с потоком (или сигналирование потока) означает, что поток должен ожидать уведомления или сигнала от одного или нескольких потоков, чтобы продолжить. Например, если поток A вызывает Thread.Join метод потока B, поток A блокируется до завершения потока B. Примитивы синхронизации, описанные в предыдущем разделе, предлагают другой механизм для передачи сигнала: освобождая блокировку, поток уведомляет другой поток о том, что может продолжить работу, получив блокировку.
В этом разделе описываются дополнительные конструкции сигналов, предоставляемые .NET.
EventWaitHandle, AutoResetEvent, ManualResetEvent и ManualResetEventSlim классы
Класс System.Threading.EventWaitHandle представляет событие синхронизации потоков.
Событие синхронизации может находиться в несигнальном или сигнальном состоянии. Если состояние события не указано, поток, вызывающий перегрузку события WaitOne , блокируется до тех пор, пока событие не будет сигнализовано. Метод EventWaitHandle.Set переводит состояние события в сигнализирующее.
Поведение EventWaitHandle, который был сигнализирован, зависит от его режима сброса:
- Созданный EventWaitHandle с помощью флага EventResetMode.AutoReset автоматически сбрасывается после завершения одного ожидающего потока. Это как турникет, который пропускает только один поток каждый раз, когда его активируют. Класс System.Threading.AutoResetEvent, производный от EventWaitHandle, отражает это поведение.
- Флаг EventWaitHandle, созданный с помощью EventResetMode.ManualReset, остается в состоянии сигнализации до тех пор, пока не будет вызван его метод Reset. Это как ворота, которые закрыты, пока не получат сигнал, а затем остаются открытыми, пока кто-то не закроет их. Класс System.Threading.ManualResetEvent, производный от EventWaitHandle, отражает это поведение. Класс System.Threading.ManualResetEventSlim является упрощенной альтернативой ManualResetEvent.
В Windows можно использовать EventWaitHandle для межпроцессной синхронизации. Для этого создайте экземпляр, представляющий именованное EventWaitHandle событие синхронизации системы с помощью одного из конструкторов EventWaitHandle , указывающих имя или EventWaitHandle.OpenExisting метод.
Дополнительные сведения см. в статье EventWaitHandle . Справочные сведения об API см. в разделе EventWaitHandle, AutoResetEventManualResetEventи ManualResetEventSlim.
Класс CountdownEvent
Класс System.Threading.CountdownEvent представляет событие, которое становится заданным, когда его число равно нулю. Пока CountdownEvent.CurrentCount больше нуля, поток, вызывающий CountdownEvent.Wait, блокируется. Вызов CountdownEvent.Signal для уменьшения количества событий.
В отличие от ManualResetEvent или ManualResetEventSlim, который позволяет разблокировать несколько потоков с сигналом из одного потока, CountdownEvent можно использовать для разблокировки одного или нескольких потоков с сигналами из нескольких потоков.
Дополнительные сведения см. в статье CountdownEvent и справочнике CountdownEvent по API.
Класс Барьера
Класс System.Threading.Barrier представляет барьер выполнения потока. Поток, вызывающий метод Barrier.SignalAndWait, сигнализирует о том, что он достиг барьера, и ожидает, пока другие потоки участников не достигнут барьера. Когда все потоки участников достигают барьера, они проходят дальше, и барьер сбрасывается и может использоваться снова.
Вы можете использовать, Barrier если один или несколько потоков требуют результатов других потоков, прежде чем переходить к следующему этапу вычислений.
Дополнительные сведения см. в статье "Барьер " и справочнике Barrier по API.
взаимоблокируемый класс
Класс System.Threading.Interlocked предоставляет статические методы, которые выполняют простые атомарные операции с переменной. Эти атомарные операции включают сложение, инкремент и декремент, обмен и условный обмен, зависящий от сравнения, и операции чтения 64-разрядного целого числа.
Для получения дополнительной информации см. справочник API Interlocked.
Структура SpinWait
Структура System.Threading.SpinWait обеспечивает поддержку ожидания на основе спина. Возможно, вы захотите использовать его, когда потоку необходимо ждать, пока событие будет сигнализировано или выполнится какое-то условие, но предполагаемое время ожидания меньше, чем требуемое для использования дескриптора ожидания или иным образом блокирования потока. С помощью SpinWait можно указать короткий период времени ожидания во время ожидания, а затем отдать управление (например, ожидая или заснув), только если условие не было выполнено в заданное время.
Дополнительные сведения см. в статье SpinWait и справочнике SpinWait по API.