похоже, что в pthreads нет эквивалента спин-блокировке.
Спинлоки часто считаются неправильным инструментом в пользовательском пространстве, потому что нет способа отключить вытеснение потока, пока Спинлок удерживается (в отличие от ядра). Таким образом, поток может получить спин-блокировку, а затем получить прерывание, в результате чего все остальные потоки, пытающиеся получить спин-блокировку, вращаются без необходимости (и если эти потоки имеют более высокий приоритет, это может привести к взаимоблокировке (потоки, ожидающие ввода-вывода, могут получить приоритет буст при пробуждении)). Это обоснование также применимо ко всем структурам данных без блокировки, если только структура данных не является действительно без ожидания (кроме многих практически полезных, кроме boost::spsc_queue
).
В ядре поток, заблокировавший спин-блокировку, не может быть прерван или прерван до того, как освободит спин-блокировку. И именно поэтому там уместны спин-блокировки (когда RCU
не может быть использован).
На Linux, можно предотвратить вытеснение (не уверен, если полностью, но были недавние ядро меняется к такому желательному эффекту), используя изолированные ядра ЦП и потоки FIFO в реальном времени, закрепленные на этих изолированных ядрах. Но это требует преднамеренной конфигурации ядра / машины и приложения, разработанного для использования этой конфигурации. Тем не менее, люди используют такую настройку для критически важных для бизнеса приложений вместе с незадействованными (но не без ожидания) структурами данных в пространстве пользователя.
При Linux имеется адаптивный мьютекс PTHREAD_MUTEX_ADAPTIVE_NP
, который вращается в течение ограниченного числа итераций перед блокировкой в ядре (аналогично InitializeCriticalSectionAndSpinCount
). Однако этот мьютекс нельзя использовать через интерфейс std::mutex
, поскольку нет возможности настроить непереносимый pthread_mutexattr_t
перед инициализацией pthread_mutex_t
.
Никто не может включить совместное использование процессов, робостность, проверку ошибок или предотвращение инверсии приоритетов через интерфейс std::mutex
. На практике люди пишут свои собственные оболочки pthread_mutex_t
, которые позволяют устанавливать желаемые атрибуты мьютекса; вместе с соответствующей оболочкой для условных переменных. Стандартные замки типа std::unique_lock
и std::lock_guard
можно использовать повторно.
IMO, могут быть условия для установки желаемых свойств мьютекса и условных переменных в API std::
, например, предоставление конструктора protected
для производных классов, которые инициализируют это native_handle
, но не существует , То, что native_handle
выглядит хорошей идеей для выполнения платформо-специфических вещей c, однако, для производного класса должен быть конструктор, чтобы иметь возможность соответствующим образом его инициализировать. После инициализации мьютекса или условной переменной это native_handle
практически бесполезно. Если только идея не состояла в том, чтобы передать только эти native_handle
API (C язык), которые ожидают указатель или ссылку на инициализированный pthread_mutex_t
.
Существует еще один пример Boost Стандарт / C ++ не принимает семафоры на том основании, что они слишком большие веревки, чтобы повеситься, и что мьютекс (по сути, двоичный семафор) и условная переменная являются более фундаментальными и более гибкими примитивами синхронизации, из которых Семафор может быть построен .
С точки зрения стандарта C ++ это, вероятно, правильные решения, поскольку обучение пользователей правильному использованию спинлок и семафоров со всеми нюансами является сложной задачей. В то время как продвинутые пользователи могут вытащить упаковку для pthread_spinlock_t
без особых усилий .