Почему нет std :: эквивалента pthread_spinlock_t, как для pthread_mutex_t & std :: mutex? - PullRequest
4 голосов
/ 30 апреля 2020

Я справедливо использовал pthreads для параллельных программ, в основном использующих спин-блокировки, мьютексы и условные переменные.

Я начал изучать многопоточность, используя std :: thread и std :: mutex, и я заметил, что в pthreads нет эквивалента спин-блокировки.

Кто-нибудь знает, почему это так?

Ответы [ 2 ]

7 голосов
/ 30 апреля 2020

похоже, что в 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 без особых усилий .

2 голосов
/ 30 апреля 2020

Вы правы, в пространстве имен std нет реализации спин-блокировки. Спин-блокировка - отличная концепция, но в пользовательском пространстве она, как правило, довольно скудная. ОС не знает, что ваш процесс хочет вращаться, и обычно вы можете получить худшие результаты, чем использование мьютекса. Следует отметить, что на нескольких платформах реализовано оптимистическое вращение c, поэтому мьютекс может выполнять действительно хорошую работу. Кроме того, настройка времени для «паузы» между каждой итерацией l oop может быть нетривиальной и переносимой, и требуется точная настройка. TL; DR не используйте спин-блокировку в пространстве пользователя, если вы действительно не уверены в том, что делаете.

C ++ Обсуждение темы

Статья, объясняющая как написать спин-блокировку с тестом

Ответ Линуса Торвальдса о статье выше, объясняющей, почему это плохая идея

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...