[thread.req] # 32 Concurrency support library [[thread]](./#thread) ## 32.2 Requirements [thread.req] ### [32.2.1](#paramname) Template parameter names [[thread.req.paramname]](thread.req.paramname) [1](#paramname-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L31) Throughout this Clause, the names of template parameters are used to express type requirements[.](#paramname-1.sentence-1) Predicate is a function object type ([[function.objects]](function.objects "22.10 Function objects"))[.](#paramname-1.sentence-2) Let pred denote an lvalue of type Predicate[.](#paramname-1.sentence-3) Then the expression pred() shall be well-formed and the type decltype(pred()) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2 Boolean testability"))[.](#paramname-1.sentence-4) The return value of pred(), converted to bool, yields true if the corresponding test condition is satisfied, andfalse otherwise[.](#paramname-1.sentence-5) If a template parameter is named Clock, the corresponding template argument shall be a type C that meets the [*Cpp17Clock*](time.clock.req#:Cpp17Clock "30.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock requirements")); the program is ill-formed if is_clock_v is false[.](#paramname-1.sentence-6) ### [32.2.2](#exception) Exceptions [[thread.req.exception]](thread.req.exception) [1](#exception-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L49) Some functions described in this Clause are specified to throw exceptions of typesystem_error ([[syserr.syserr]](syserr.syserr "19.5.8 Class system_­error"))[.](#exception-1.sentence-1) Such exceptions are thrown if any of the function's error conditions is detected or a call to an operating system or other underlying API results in an error that prevents the library function from meeting its specifications[.](#exception-1.sentence-2) Failure to allocate storage is reported as described in [[res.on.exception.handling]](res.on.exception.handling "16.4.6.14 Restrictions on exception handling")[.](#exception-1.sentence-3) [*Example [1](#exception-example-1)*: Consider a function in this Clause that is specified to throw exceptions of typesystem_error and specifies error conditions that includeoperation_not_permitted for a thread that does not have the privilege to perform the operation[.](#exception-1.sentence-4) Assume that, during the execution of this function, an errno of EPERM is reported by a POSIX API call used by the implementation[.](#exception-1.sentence-5) Since POSIX specifies an errno of EPERM when “the caller does not have the privilege to perform the operation”, the implementation maps EPERM to anerror_condition of operation_not_permitted ([[syserr]](syserr "19.5 System error support")) and an exception of type system_error is thrown[.](#exception-1.sentence-6) — *end example*] [2](#exception-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L71) The error_code reported by such an exception's code() member function compares equal to one of the conditions specified in the function's error condition element[.](#exception-2.sentence-1) ### [32.2.3](#native) Native handles [[thread.req.native]](thread.req.native) [1](#native-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L78) Several classes described in this Clause have members native_handle_type andnative_handle[.](#native-1.sentence-1) The presence of these members and their semantics isimplementation-defined[.](#native-1.sentence-2) [*Note [1](#native-note-1)*: These members allow implementations to provide access to implementation details[.](#native-1.sentence-3) Their names are specified to facilitate portable compile-time detection[.](#native-1.sentence-4) Actual use of these members is inherently non-portable[.](#native-1.sentence-5) — *end note*] ### [32.2.4](#timing) Timing specifications [[thread.req.timing]](thread.req.timing) [1](#timing-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L90) Several functions described in this Clause take an argument to specify a timeout[.](#timing-1.sentence-1) These timeouts are specified as either a duration or a time_point type as specified in [[time]](time "30 Time library")[.](#timing-1.sentence-2) [2](#timing-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L95) Implementations necessarily have some delay in returning from a timeout[.](#timing-2.sentence-1) Any overhead in interrupt response, function return, and scheduling induces a “quality of implementation” delay, expressed as duration Di[.](#timing-2.sentence-2) Ideally, this delay would be zero[.](#timing-2.sentence-3) Further, any contention for processor and memory resources induces a “quality of management” delay, expressed as durationDm[.](#timing-2.sentence-4) The delay durations may vary from timeout to timeout, but in all cases shorter is better[.](#timing-2.sentence-5) [3](#timing-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L102) The functions whose names end in _for take an argument that specifies a duration[.](#timing-3.sentence-1) These functions produce relative timeouts[.](#timing-3.sentence-2) Implementations should use a steady clock to measure time for these functions[.](#timing-3.sentence-3)[293](#footnote-293 "Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation.") Given a duration argument Dt, the real-time duration of the timeout is Dt+Di+Dm[.](#timing-3.sentence-4) [4](#timing-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L113) The functions whose names end in _until take an argument that specifies a time point[.](#timing-4.sentence-1) These functions produce absolute timeouts[.](#timing-4.sentence-2) Implementations should use the clock specified in the time point to measure time for these functions[.](#timing-4.sentence-3) Given a clock time point argument Ct, the clock time point of the return from timeout should be Ct+Di+Dm when the clock is not adjusted during the timeout[.](#timing-4.sentence-4) If the clock is adjusted to the time Ca during the timeout, the behavior should be as follows: - [(4.1)](#timing-4.1) If Ca>Ct, the waiting function should wake as soon as possible, i.e., Ca+Di+Dm, since the timeout is already satisfied[.](#timing-4.1.sentence-1) This specification may result in the total duration of the wait decreasing when measured against a steady clock[.](#timing-4.1.sentence-2) - [(4.2)](#timing-4.2) If Ca≤Ct, the waiting function should not time out until Clock​::​now() returns a time Cn≥Ct, i.e., waking at Ct+Di+Dm[.](#timing-4.2.sentence-1) [*Note [1](#timing-note-1)*: When the clock is adjusted backwards, this specification can result in the total duration of the wait increasing when measured against a steady clock[.](#timing-4.2.sentence-2) When the clock is adjusted forwards, this specification can result in the total duration of the wait decreasing when measured against a steady clock[.](#timing-4.2.sentence-3) — *end note*] An implementation returns from such a timeout at any point from the time specified above to the time it would return from a steady-clock relative timeout on the difference between Ct and the time point of the call to the _until function[.](#timing-4.sentence-6) *Recommended practice*: Implementations should decrease the duration of the wait when the clock is adjusted forwards[.](#timing-4.sentence-7) [5](#timing-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L146) [*Note [2](#timing-note-2)*: If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these timeouts can fail to provide useful functionality[.](#timing-5.sentence-1) — *end note*] [6](#timing-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L152) The resolution of timing provided by an implementation depends on both operating system and hardware[.](#timing-6.sentence-1) The finest resolution provided by an implementation is called the[*native resolution*](#def:native_resolution)[.](#timing-6.sentence-2) [7](#timing-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L157) Implementation-provided clocks that are used for these functions meet the[*Cpp17TrivialClock*](time.clock.req#:Cpp17TrivialClock "30.3 Cpp17Clock requirements [time.clock.req]") requirements ([[time.clock.req]](time.clock.req "30.3 Cpp17Clock requirements"))[.](#timing-7.sentence-1) [8](#timing-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L161) A function that takes an argument which specifies a timeout will throw if, during its execution, a clock, time point, or time duration throws an exception[.](#timing-8.sentence-1) Such exceptions are referred to as [*timeout-related exceptions*](#def:timeout-related_exceptions)[.](#timing-8.sentence-2) [*Note [3](#timing-note-3)*: Instantiations of clock, time point and duration types supplied by the implementation as specified in [[time.clock]](time.clock "30.7 Clocks") do not throw exceptions[.](#timing-8.sentence-3) — *end note*] [293)](#footnote-293)[293)](#footnoteref-293) Implementations for which standard time units are meaningful will typically have a steady clock within their hardware implementation[.](#footnote-293.sentence-1) ### [32.2.5](#lockable) Requirements for *Cpp17Lockable* types [[thread.req.lockable]](thread.req.lockable) #### [32.2.5.1](#lockable.general) General [[thread.req.lockable.general]](thread.req.lockable.general) [1](#lockable.general-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L174) An [*execution agent*](#def:execution_agent "32.2.5.1 General [thread.req.lockable.general]") is an entity such as a thread that may perform work in parallel with other execution agents[.](#lockable.general-1.sentence-1) [*Note [1](#lockable.general-note-1)*: Implementations or users can introduce other kinds of agents such as processes or thread-pool tasks[.](#lockable.general-1.sentence-2) — *end note*] The calling agent is determined by context, e.g., the calling thread that contains the call, and so on[.](#lockable.general-1.sentence-3) [2](#lockable.general-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L184) [*Note [2](#lockable.general-note-2)*: Some lockable objects are “agent oblivious” in that they work for any execution agent model because they do not determine or store the agent's ID (e.g., an ordinary spin lock)[.](#lockable.general-2.sentence-1) — *end note*] [3](#lockable.general-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L191) The standard library templates unique_lock ([[thread.lock.unique]](thread.lock.unique "32.6.5.4 Class template unique_­lock")),shared_lock ([[thread.lock.shared]](thread.lock.shared "32.6.5.5 Class template shared_­lock")),scoped_lock ([[thread.lock.scoped]](thread.lock.scoped "32.6.5.3 Class template scoped_­lock")),lock_guard ([[thread.lock.guard]](thread.lock.guard "32.6.5.2 Class template lock_­guard")), lock,try_lock ([[thread.lock.algorithm]](thread.lock.algorithm "32.6.6 Generic locking algorithms")), andcondition_variable_any ([[thread.condition.condvarany]](thread.condition.condvarany "32.7.5 Class condition_­variable_­any")) all operate on user-supplied lockable objects[.](#lockable.general-3.sentence-1) The [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements, the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements, the [*Cpp17TimedLockable*](#:Cpp17TimedLockable "32.2.5.4 Cpp17TimedLockable requirements [thread.req.lockable.timed]") requirements, the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements, and the [*Cpp17SharedTimedLockable*](#:Cpp17SharedTimedLockable "32.2.5.6 Cpp17SharedTimedLockable requirements [thread.req.lockable.shared.timed]") requirements list the requirements imposed by these library types in order to acquire or release ownership of a lock by a given execution agent[.](#lockable.general-3.sentence-2) [*Note [3](#lockable.general-note-3)*: The nature of any lock ownership and any synchronization it entails are not part of these requirements[.](#lockable.general-3.sentence-3) — *end note*] [4](#lockable.general-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L209) A lock on an object m is said to be - [(4.1)](#lockable.general-4.1) a [*non-shared lock*](#def:lock,non-shared "32.2.5.1 General [thread.req.lockable.general]") if it is acquired by a call tolock,try_lock,try_lock_for, ortry_lock_until on m, or - [(4.2)](#lockable.general-4.2) a [*shared lock*](#def:lock,shared "32.2.5.1 General [thread.req.lockable.general]") if it is acquired by a call tolock_shared,try_lock_shared,try_lock_shared_for, ortry_lock_shared_until on m[.](#lockable.general-4.sentence-1) [*Note [4](#lockable.general-note-4)*: Only the method of lock acquisition is considered; the nature of any lock ownership is not part of these definitions[.](#lockable.general-4.sentence-2) — *end note*] #### [32.2.5.2](#lockable.basic) *Cpp17BasicLockable* requirements [[thread.req.lockable.basic]](thread.req.lockable.basic) [1](#lockable.basic-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L232) A type L meets the *Cpp17BasicLockable* requirements if the following expressions are well-formed and have the specified semantics (m denotes a value of type L)[.](#lockable.basic-1.sentence-1) [🔗](#lockable.basic-itemdecl:1) `m.lock() ` [2](#lockable.basic-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L241) *Effects*: Blocks until a lock can be acquired for the current execution agent[.](#lockable.basic-2.sentence-1) If an exception is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.basic-2.sentence-2) [🔗](#lockable.basic-itemdecl:2) `m.unlock() ` [3](#lockable.basic-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L253) *Preconditions*: The current execution agent holds a non-shared lock on m[.](#lockable.basic-3.sentence-1) [4](#lockable.basic-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L257) *Effects*: Releases a non-shared lock on m held by the current execution agent[.](#lockable.basic-4.sentence-1) [5](#lockable.basic-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L261) *Throws*: Nothing[.](#lockable.basic-5.sentence-1) #### [32.2.5.3](#lockable.req) *Cpp17Lockable* requirements [[thread.req.lockable.req]](thread.req.lockable.req) [1](#lockable.req-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L268) A type L meets the *Cpp17Lockable* requirements if it meets the [*Cpp17BasicLockable*](#:Cpp17BasicLockable "32.2.5.2 Cpp17BasicLockable requirements [thread.req.lockable.basic]") requirements and the following expressions are well-formed and have the specified semantics (m denotes a value of type L)[.](#lockable.req-1.sentence-1) [🔗](#lockable.req-itemdecl:1) `m.try_lock() ` [2](#lockable.req-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L278) *Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#lockable.req-2.sentence-1) If an exception is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.req-2.sentence-2) [3](#lockable.req-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L283) *Return type*: bool[.](#lockable.req-3.sentence-1) [4](#lockable.req-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L286) *Returns*: true if the lock was acquired, otherwise false[.](#lockable.req-4.sentence-1) #### [32.2.5.4](#lockable.timed) *Cpp17TimedLockable* requirements [[thread.req.lockable.timed]](thread.req.lockable.timed) [1](#lockable.timed-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L293) A type L meets the *Cpp17TimedLockable* requirements if it meets the [*Cpp17Lockable*](#:Cpp17Lockable "32.2.5.3 Cpp17Lockable requirements [thread.req.lockable.req]") requirements and the following expressions are well-formed and have the specified semantics (m denotes a value of type L, rel_time denotes a value of an instantiation of [duration](time.duration "30.5 Class template duration [time.duration]"), and abs_time denotes a value of an instantiation of [time_point](time.point "30.6 Class template time_­point [time.point]"))[.](#lockable.timed-1.sentence-1) [🔗](#lockable.timed-itemdecl:1) `m.try_lock_for(rel_time) ` [2](#lockable.timed-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L305) *Effects*: Attempts to acquire a lock for the current execution agent within the relative timeout ([[thread.req.timing]](#timing "32.2.4 Timing specifications")) specified by rel_time[.](#lockable.timed-2.sentence-1) The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#lockable.timed-2.sentence-2) If an exception is thrown then a lock has not been acquired for the current execution agent[.](#lockable.timed-2.sentence-3) [3](#lockable.timed-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L313) *Return type*: bool[.](#lockable.timed-3.sentence-1) [4](#lockable.timed-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L316) *Returns*: true if the lock was acquired, otherwise false[.](#lockable.timed-4.sentence-1) [🔗](#lockable.timed-itemdecl:2) `m.try_lock_until(abs_time) ` [5](#lockable.timed-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L326) *Effects*: Attempts to acquire a lock for the current execution agent before the absolute timeout ([[thread.req.timing]](#timing "32.2.4 Timing specifications")) specified by abs_time[.](#lockable.timed-5.sentence-1) The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent[.](#lockable.timed-5.sentence-2) If an exception is thrown then a lock has not been acquired for the current execution agent[.](#lockable.timed-5.sentence-3) [6](#lockable.timed-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L334) *Return type*: bool[.](#lockable.timed-6.sentence-1) [7](#lockable.timed-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L337) *Returns*: true if the lock was acquired, otherwise false[.](#lockable.timed-7.sentence-1) #### [32.2.5.5](#lockable.shared) *Cpp17SharedLockable* requirements [[thread.req.lockable.shared]](thread.req.lockable.shared) [1](#lockable.shared-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L344) A type L meets the *Cpp17SharedLockable* requirements if the following expressions are well-formed, have the specified semantics, and the expression m.try_lock_shared() has type bool (m denotes a value of type L): [🔗](#lockable.shared-itemdecl:1) `m.lock_shared() ` [2](#lockable.shared-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L355) *Effects*: Blocks until a lock can be acquired for the current execution agent[.](#lockable.shared-2.sentence-1) If an exception is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.shared-2.sentence-2) [🔗](#lockable.shared-itemdecl:2) `m.try_lock_shared() ` [3](#lockable.shared-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L367) *Effects*: Attempts to acquire a lock for the current execution agent without blocking[.](#lockable.shared-3.sentence-1) If an exception is thrown then a lock shall not have been acquired for the current execution agent[.](#lockable.shared-3.sentence-2) [4](#lockable.shared-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L373) *Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared-4.sentence-1) [🔗](#lockable.shared-itemdecl:3) `m.unlock_shared() ` [5](#lockable.shared-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L383) *Preconditions*: The current execution agent holds a shared lock on m[.](#lockable.shared-5.sentence-1) [6](#lockable.shared-6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L387) *Effects*: Releases a shared lock on m held by the current execution agent[.](#lockable.shared-6.sentence-1) [7](#lockable.shared-7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L391) *Throws*: Nothing[.](#lockable.shared-7.sentence-1) #### [32.2.5.6](#lockable.shared.timed) *Cpp17SharedTimedLockable* requirements [[thread.req.lockable.shared.timed]](thread.req.lockable.shared.timed) [1](#lockable.shared.timed-1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L398) A type L meets the *Cpp17SharedTimedLockable* requirements if it meets the [*Cpp17SharedLockable*](#:Cpp17SharedLockable "32.2.5.5 Cpp17SharedLockable requirements [thread.req.lockable.shared]") requirements, and the following expressions are well-formed, have type bool, and have the specified semantics (m denotes a value of type L,rel_time denotes a value of a specialization of chrono​::​duration, andabs_time denotes a value of a specialization of chrono​::​time_point)[.](#lockable.shared.timed-1.sentence-1) [🔗](#lockable.shared.timed-itemdecl:1) `m.try_lock_shared_for(rel_time) ` [2](#lockable.shared.timed-2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L412) *Effects*: Attempts to acquire a lock for the current execution agent within the relative timeout ([[thread.req.timing]](#timing "32.2.4 Timing specifications")) specified by rel_time[.](#lockable.shared.timed-2.sentence-1) The function will not return within the timeout specified by rel_time unless it has obtained a lock on m for the current execution agent[.](#lockable.shared.timed-2.sentence-2) If an exception is thrown then a lock has not been acquired for the current execution agent[.](#lockable.shared.timed-2.sentence-3) [3](#lockable.shared.timed-3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L421) *Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared.timed-3.sentence-1) [🔗](#lockable.shared.timed-itemdecl:2) `m.try_lock_shared_until(abs_time) ` [4](#lockable.shared.timed-4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L431) *Effects*: Attempts to acquire a lock for the current execution agent before the absolute timeout ([[thread.req.timing]](#timing "32.2.4 Timing specifications")) specified by abs_time[.](#lockable.shared.timed-4.sentence-1) The function will not return before the timeout specified by abs_time unless it has obtained a lock on m for the current execution agent[.](#lockable.shared.timed-4.sentence-2) If an exception is thrown then a lock has not been acquired for the current execution agent[.](#lockable.shared.timed-4.sentence-3) [5](#lockable.shared.timed-5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L440) *Returns*: true if the lock was acquired, false otherwise[.](#lockable.shared.timed-5.sentence-1)