После более полного прочтения документации по Solaris я смог понять основную идею, поэтому я отвечу на свой вопрос.
Какую проблему решает турникет?Какое преимущество может предложить турникет по сравнению с мьютексом?Каково отношение собственности между потоком и турникетом?(если есть).
Турникет может помочь уменьшить количество мьютексов (или любого другого блока синхронизации).Когда мы хотим защитить объект с помощью некоторого замка с помощью турникетов, замок становится легким объектом, который делегирует все операции турникету.Каждая нить может быть связана не более чем с одним турникетом.Отсюда #turnstiles ≤ #threads.Такой подход помогает уменьшить количество неактивных блокировок.Однако нет никакого явного владения между потоками и турникетами AFAIK.
Если мы уменьшим сложность этих реализаций, какова минимальная структура турникета с минимальными затратами?
Мы можем реализовать наивный турникет следующим образом.
Выделите глобальный пул Turnstiles
с операциями get
и put
(очевидно, он должен быть потокобезопасным).Стек без блокировки может быть относительно простой и эффективной реализацией для пула.TurnstileLock
- это объект, который заменит наши блокировки и мьютексы и передаст ответственность Turnstile
.TurnstileLock
содержит обнуляемый указатель на Turnstile
.
Когда какой-то поток хочет войти в критическую секцию, охраняемую TurnstileLock
, он проверяет, является ли TurnstileLock.currentTurnstile
нулевым (по умолчанию он должен быть нулевым).
- Если ноль равен, поток берет турникет из пула и присваивает ему
TurnstileLock.currentTurnstile
, увеличивает TurnstileLock.currentTurnstile.waitingCount
и входит в критическую секцию. - В противном случае поток долженувеличивайте
TurnstileLock.currentTurnstile.waitingCount
и ждите некоторую переменную условия, которая должна быть доступна через currentTurnstile
Когда какой-либо поток хочет покинуть критическую секцию (или снять блокировку), он должен проверить, TurnstileLock.currentTurnstile.waitingCount > 0
(после уменьшения)
- Если да, то необходимо уведомить переменную условия, в которой спят другие потоки.
- Иначе положить
TurnstileLock.currentTurnstile
обратно в пул и установить TurnstileLock.currentTurnstile
до нуля