mutex types Стандартные библиотеки типовmutex, recursive_mutex,timed_mutex,recursive_timed_mutex, shared_mutex, иshared_timed_mutex. Они должны соответствовать требованиям, изложенным в этом разделе. В этом описанииm обозначает объект типа мьютекса.
Типы мьютексов должны бытьDefaultConstructible иDestructible. Если инициализация объекта типа мьютекса не удалась,system_error должно быть выброшено исключение типа . Типы мьютексов нельзя копировать или перемещать.
Условия ошибки для кодов ошибок, если таковые имеются, сообщаемые функциями-членами типов мьютексов, должны быть:
resource_unavailable_try_again - если какой-либо управляемый тип дескриптора недоступен.
operation_not_permitted - если поток не имеет права выполнять операцию.
invalid_argument - если какой-либо собственный тип дескриптора, манипулируемый как часть конструкции мьютекса, неверен.
Реализация должна обеспечивать операции блокировки и разблокировки, как описано ниже. В целях определения наличия гонки данных они ведут себя как атомарные операции ([intro.multithread]). Операции блокировки и разблокировки на одном мьютексе должны выполняться в едином общем порядке. [ Note: Это можно рассматривать какmodification order мьютекс. ] [ Создание и уничтожение объекта типа мьютекса не обязательно должно быть потокобезопасным; следует использовать другую синхронизацию, чтобы гарантировать, что объекты мьютекса инициализированы и видны другим потокам. ] — end note Note: — end note
Requires: Еслиm имеет типmutex,timed_mutex, shared_mutexилиshared_timed_mutex, вызывающий поток не является владельцем мьютекса.
Effects: Блокирует вызывающий поток до тех пор, пока для вызывающего потока не будет получено право владения мьютексом.
Synchronization: Предыдущиеunlock() операции на одном и том же объекте являются synchronize with этой операцией.
Throws:system_error когда требуется исключение ([thread.req.exception]).
Requires: Еслиm имеет типmutex,timed_mutex, shared_mutexилиshared_timed_mutex, вызывающий поток не является владельцем мьютекса.
Effects: Пытается получить право собственности на мьютекс для вызывающего потока без блокировки. Если право собственности не получено, нет никакого эффекта иtry_lock() немедленно возвращается. Реализация может не получить блокировку, даже если она не удерживается каким-либо другим потоком. [ Note: Этот ложный сбой обычно встречается редко, но допускает интересные реализации, основанные на простом сравнении и обмене (пункт[atomics]). ] Реализация должна гарантировать, что не будет последовательного возврата в отсутствие конкурирующих захватов мьютексов. — end note try_lock() false
Returns:true если право собственности на мьютекс было получено для вызывающего потока, в противном случаеfalse.
Synchronization: Еслиtry_lock() возвращаетсяtrue, предыдущиеunlock() операции с тем же объектомsynchronize with это операция. [ Note: Такlock() как не синхронизируется с неудачным последующим try_lock(), правила видимости достаточно слабы, чтобы о состоянии после отказа было бы мало что известно, даже при отсутствии ложных отказов. ] — end note
Synchronization: Эта операция являетсяsynchronizes with последующими операциями блокировки, которые получают право собственности на один и тот же объект.
namespace std { class mutex { public: constexpr mutex() noexcept; ~mutex(); mutex(const mutex&) = delete; mutex& operator=(const mutex&) = delete; void lock(); bool try_lock(); void unlock(); using native_handle_type = implementation-defined; // See [thread.req.native] native_handle_type native_handle(); // See [thread.req.native] }; }
Классmutex предоставляет нерекурсивный мьютекс с семантикой исключительного владения. Если один поток владеет объектом мьютекса, попытки другого потока получить право владения этим объектом будут неудачными (дляtry_lock()) или блокируются (для lock()) до тех пор, пока поток-владелец не освободит владение с помощью вызова unlock().
[ Note: После того, как потокA вызвалunlock(), освободив мьютекс, другой потокB может заблокировать тот же мьютекс, заметить, что он больше не используется, разблокировать его и уничтожить до того, как поток,A кажется, вернется из своего вызова разблокировки. Для правильной обработки таких сценариев требуются реализации, если потокA не обращается к мьютексу после возврата вызова разблокировки. Эти случаи обычно возникают, когда объект со счетчиком ссылок содержит мьютекс, который используется для защиты счетчика ссылок. ] — end note
Классmutex должен удовлетворять всем требованиямmutex requirements. Это должен быть standard-layout class.
[ Note: Программа может заблокироваться, если поток, которому принадлежитmutex объект, вызывает lock() этот объект. Если реализация может обнаружить тупик,resource_deadlock_would_occur может наблюдаться состояние ошибки. ] — end note
namespace std { class recursive_mutex { public: recursive_mutex(); ~recursive_mutex(); recursive_mutex(const recursive_mutex&) = delete; recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); bool try_lock() noexcept; void unlock(); using native_handle_type = implementation-defined; // See [thread.req.native] native_handle_type native_handle(); // See [thread.req.native] }; }
Классrecursive_mutex предоставляет рекурсивный мьютекс с семантикой исключительного владения. Если один поток владеетrecursive_mutex объектом, попытки другого потока получить право владения этим объектом завершатся ошибкой (дляtry_lock()) или заблокируются (дляlock()) до тех пор, пока первый поток полностью не освободит владение.
Классrecursive_mutex должен удовлетворять всем требованиямmutex requirements. Это должен быть standard-layout class.
Поток, которому принадлежитrecursive_mutex объект, может получить дополнительные уровни владения путем вызова этого объектаlock() илиtry_lock() для этого объекта. Не указано, сколько уровней владения может быть получено одним потоком. Если поток уже получил максимальный уровень владенияrecursive_mutex объектом, дополнительные вызовыtry_lock() должны завершиться ошибкой, а дополнительные вызовы lock() вызовут исключение типаsystem_error. Поток должен вызыватьunlock() один раз для каждого уровня владения, полученного вызовами lock() иtry_lock(). Только когда все уровни владения высвобождены, право владения может быть приобретено другим потоком.