Section: 32.6.4.4 [thread.sharedmutex.requirements] Status: C++14 Submitter: Daniel Krügler Opened: 2013-08-30 Last modified: 2016-01-28
Priority: Not Prioritized
View all issues with C++14 status.
Discussion:
Albeit shared mutex types refine timed mutex types, the requirements imposed on the corresponding required member function expressions are inconsistent in several aspects, most probably because failing synchronisation with wording changes for timed mutexes applied by some issues:
Due to acceptance of N3568 a wording phrase came in 32.6.4.4 [thread.sharedmutex.requirements] p26,
Effects: If the tick period of
rel_time
is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period. […]
while a very similar one had been removed for 32.6.4.3 [thread.timedmutex.requirements] by LWG 2091.
Having this guaranteed effect fortry_lock_shared_for
but not for try_lock_for
seems inconsistent
and astonishing.
If the actual intended restriction imposed onto the implementation is to forbid early wakeups here, we should ensure that
to hold for timed mutex's try_lock_for
as well. Note that the rationale provided for LWG 2091 was
a potential late wakeup situation, but it seems that there is no implementation restriction that prevents early wakeups.
The shared-lock requirements for any *lock*()
functions don't provide the guarantee that "If an exception is thrown then
a lock shall not have been acquired for the current execution agent.". For other mutex types this guarantee can be derived from
the corresponding TimedLockable
requirements, but there are no SharedLockable
requirements.
The shared-lock requirements for *lock_for/_until()
functions require "Throws: Nothing."
instead of "Throws: Timeout-related exceptions (30.2.4)." which had been added by LWG 2093, because user-provided
clocks, durations, or time points may throw exceptions.
With the addition of std::shared_mutex
, the explicit lists of 32.6.4.2 [thread.mutex.requirements.mutex] p7+15,
Requires: If
m
is of typestd::mutex
orstd::timed_mutex
, the calling thread does not own the mutex.
and of 32.6.4.3 [thread.timedmutex.requirements] p4+11,
Requires: If
m
is of typestd::timed_mutex
, the calling thread does not own the mutex.
are incomplete and should add the non-recursive std::shared_mutex
as well.
[2014-02-16: Moved as Immediate]
Proposed resolution:
This wording is relative to N3691.
Change 32.6.4.2 [thread.mutex.requirements.mutex] p7+15 as indicated:
-6- The expression
m.lock()
shall be well-formed and have the following semantics:-7- Requires: If
m
is of typestd::mutex
or,std::timed_mutex
, orstd::shared_mutex
, the calling thread does not own the mutex.[…]
-14- The expression
m.try_lock()
shall be well-formed and have the following semantics:-15- Requires: If
m
is of typestd::mutex
or,std::timed_mutex
, orstd::shared_mutex
, the calling thread does not own the mutex.
Change 32.6.4.3 [thread.timedmutex.requirements] p4+11 as indicated:
-3- The expression
m.try_lock_for(rel_time)
shall be well-formed and have the following semantics:-4- Requires: If
m
is of typestd::timed_mutex
orstd::shared_mutex
, the calling thread does not own the mutex.[…]
-10- The expression
m.try_lock_until(abs_time)
shall be well-formed and have the following semantics:-11- Requires: If
m
is of typestd::timed_mutex
orstd::shared_mutex
, the calling thread does not own the mutex.
Change 32.6.4.4 [thread.sharedmutex.requirements] as indicated:
-3- The expression
m.lock_shared()
shall be well-formed and have the following semantics:-4- Requires: The calling thread has no ownership of the mutex.
-5- Effects: Blocks the calling thread until shared ownership of the mutex can be obtained for the calling thread. If an exception is thrown then a shared lock shall not have been acquired for the current thread. […]-24- The expression
m.try_lock_shared_for(rel_time)
shall be well-formed and have the following semantics:-25- Requires: The calling thread has no ownership of the mutex.
-26- Effects:If the tick period ofAttempts to obtain shared lock ownership for the calling thread within the relative timeout (30.2.4) specified byrel_time
is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period.rel_time
. If the time specified byrel_time
is less than or equal torel_time.zero()
, the function attempts to obtain ownership without blocking (as if by callingtry_lock_shared()
). The function shall return within the timeout specified byrel_time
only if it has obtained shared ownership of the mutex object. [Note: As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note] If an exception is thrown then a shared lock shall not have been acquired for the current thread. […] -30- Throws:NothingTimeout-related exceptions (32.2.4 [thread.req.timing]).-31- The expression
m.try_lock_shared_until(abs_time)
shall be well-formed and have the following semantics:-32- Requires: The calling thread has no ownership of the mutex.
-33- Effects: The function attempts to obtain shared ownership of the mutex. Ifabs_time
has already passed, the function attempts to obtain shared ownership without blocking (as if by callingtry_lock_shared()
). The function shall return before the absolute timeout (30.2.4) specified byabs_time
only if it has obtained shared ownership of the mutex object. [Note: As withtry_lock()
, there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note] If an exception is thrown then a shared lock shall not have been acquired for the current thread. […] -37- Throws:NothingTimeout-related exceptions (32.2.4 [thread.req.timing]).