семафор - синхронизация потоков c++




Как мьютексы действительно работают? (3)

Идея мьютексов состоит в том, чтобы разрешить доступ только одному потоку к разделу памяти одновременно. Если один поток блокирует мьютекс, любые другие попытки блокировки будут блокироваться, пока не разблокируется первый. Однако как это реализовано? Чтобы заблокировать себя, мьютекс должен установить бит где-то, что говорит, что он заблокирован. Но что, если второй мьютекс читает одновременно с первым? Хуже того, что если они оба заблокируют мьютекс одновременно? Мьютекс поддался бы той же проблеме, которую он призван предотвратить.

Как мьютексы действительно работают?


Вот краткий обзор того, что мьютекс должен работать, это сокращенная форма моей полной статьи Как работает мьютекс?

  • В памяти есть целое число, которое представляет заблокированное состояние со значением 1 или 0.
  • compare_and_swap нужна атомарная функция compare_and_swap которая может атомарно попытаться изменить это значение и сообщить, успешно ли оно выполнено. Это позволяет потоку одновременно проверять и изменять состояние.
  • ОС должна предоставить функцию ожидания в случае блокировки мьютекса. В Linux низкоуровневая функция - futex . Это поместит поток в очередь, а также отслеживает целое число в памяти.
  • Используемые операции также включают в себя ограждения данных, чтобы предотвратить видимость изменений в памяти до блокировки и быть полностью доступными после блокировки.

Все, что вам нужно, это сделать это атомарно. Это может быть обеспечено аппаратными средствами, такими как атомарные инструкции сравнения и обмена, или операционной системой через системные вызовы. Оказавшись в домене ОС, довольно легко убедиться, что только один поток пытается заблокировать мьютекс.

На практике оба подхода объединены. Смотрите, например, Linux-фьютексы.


Простая реализация, которая использовалась в прошлом, заключается в использовании атомарной инструкции «блокировка и обмен» на уровне процессора. Это специальная инструкция, которая атомарно меняет заданное значение на значение в некоторой ячейке памяти.

Поток может получить такой мьютекс, пытаясь поменять значение 1 в ячейке памяти. Если значение возвращается как 0, тогда поток предположил бы, что у него есть мьютекс, и продолжил бы. В противном случае, если возвращаемое значение равно 1, то поток будет знать, что какой-то другой поток в настоящее время имеет мьютекс. В этом случае он будет ждать, пока не попробуете снова.

Выше приведено очень упрощенное описание того, что может произойти в простой системе. Реальные операционные системы намного сложнее в наши дни.





mutex