Синхронизация выполнения нескольких потоков

Чтобы избежать состояния гонки и взаимоблокировок, необходимо синхронизировать доступ нескольких потоков к общим ресурсам. Синхронизация также необходима, чтобы обеспечить выполнение взаимозависимого кода в правильной последовательности.

Существует ряд объектов, дескрипторы которых можно использовать для синхронизации нескольких потоков. К этим объектам относятся:

  • Входные буферы консоли
  • События
  • Mutexes
  • Процессы
  • Семафоры
  • Потоки
  • Таймеры

Состояние каждого из этих объектов либо сигнализируется, либо не сообщается. При указании дескриптора для любого из этих объектов в вызове одной из функций ожидания выполнение вызывающего потока блокируется до тех пор, пока состояние указанного объекта не станет сигналом.

Некоторые из этих объектов полезны при блокировке потока до тех пор, пока не произойдет какое-то событие. Например, дескриптор буфера ввода консоли сигнализирует о непрочтенных входных данных, например нажатии клавиши или нажатии кнопки мыши. Дескрипторы процессов и потоков сигнализируются при завершении процесса или потока. Это позволяет процессу, например, создать дочерний процесс, а затем заблокировать его собственное выполнение до завершения нового процесса.

Другие объекты полезны для защиты общих ресурсов от одновременного доступа. Например, каждый из нескольких потоков может иметь дескриптор объекта мьютекса. Перед доступом к общему ресурсу потоки должны вызвать одну из функций ожидания , чтобы дождаться передачи сигнала о состоянии мьютекса. Когда мьютекс получает сигнал, для доступа к ресурсу освобождается только один ожидающие потоки. Состояние мьютекса немедленно сбрасывается до не сигнального, поэтому все другие ожидающие потоки остаются заблокированными. После завершения работы с ресурсом поток должен задать состояние мьютекса в значение Signaled, чтобы разрешить другим потокам доступ к ресурсу.

Для потоков одного процесса объекты критического раздела обеспечивают более эффективные средства синхронизации, чем мьютексы. Критически важный раздел используется как мьютекс, чтобы один поток за раз мог использовать защищенный ресурс. Поток может использовать функцию EnterCriticalSection для запроса владения критически важным разделом. Если он уже принадлежит другому потоку, запрашивающий поток блокируется. Поток может использовать функцию TryEnterCriticalSection для запроса владения критически важным разделом, не блокируя при сбое получения критического раздела. После получения права владения поток может свободно использовать защищенный ресурс. Выполнение других потоков процесса не затрагивается, если они не попытаются войти в тот же критический раздел.

Функция WaitForInputIdle заставляет поток ожидать инициализации указанного процесса и ожидать ввода данных пользователем без ожидания ввода. Вызов WaitForInputIdle может быть полезен для синхронизации родительских и дочерних процессов, так как CreateProcess возвращает, не дожидаясь завершения инициализации дочернего процесса.

Дополнительные сведения см. в разделе Синхронизация.