30 Thread support library [thread]

30.4 Mutual exclusion [thread.mutex]

30.4.1 Mutex requirements [thread.mutex.requirements]

30.4.1.4 Shared timed mutex types [thread.sharedtimedmutex.requirements]

The standard library type std::shared_timed_mutex is a shared timed mutex type. Shared timed mutex types shall meet the requirements of timed mutex types ([thread.timedmutex.requirements]), and additionally shall meet the requirements set out below. In this description, m denotes an object of a mutex type, rel_type denotes an object of an instantiation of duration ([time.duration]), and abs_time denotes an object of an instantiation of time_point ([time.point]).

In addition to the exclusive lock ownership mode specified in [thread.mutex.requirements.mutex], shared mutex types provide a shared lock ownership mode. Multiple execution agents can simultaneously hold a shared lock ownership of a shared mutex type. But no execution agent shall hold a shared lock while another execution agent holds an exclusive lock on the same shared mutex type, and vice-versa. The maximum number of execution agents which can share a shared lock on a single shared mutex type is unspecified, but shall be at least 10000. If more than the maximum number of execution agents attempt to obtain a shared lock, the excess execution agents shall block until the number of shared locks are reduced below the maximum amount by other execution agents releasing their shared lock.

The expression m.lock_shared() shall be well-formed and have the following semantics:

Requires: The calling thread has no ownership of the mutex.

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.

Postcondition: The calling thread has a shared lock on the mutex.

Return type: void.

Synchronization: Prior unlock() operations on the same object shall synchronize with ([intro.multithread]) this operation.

Throws: system_error when an exception is required ([thread.req.exception]).

Error conditions:

  • operation_not_permitted — if the thread does not have the privilege to perform the operation.

  • resource_deadlock_would_occur — if the implementation detects that a deadlock would occur.

  • device_or_resource_busy — if the mutex is already locked and blocking is not possible.

The expression m.unlock_shared() shall be well-formed and have the following semantics:

Requires: The calling thread shall hold a shared lock on the mutex.

Effects: Releases a shared lock on the mutex held by the calling thread.

Return type: void.

Synchronization: This operation synchronizes with ([intro.multithread]) subsequent lock() operations that obtain ownership on the same object.

Throws: Nothing.

The expression m.try_lock_shared() shall be well-formed and have the following semantics:

Requires: The calling thread has no ownership of the mutex.

Effects: Attempts to obtain shared ownership of the mutex for the calling thread without blocking. If shared ownership is not obtained, there is no effect and try_lock_shared() immediately returns. An implementation may fail to obtain the lock even if it is not held by any other thread.

Return type: bool.

Returns: true if the shared ownership lock was acquired, false otherwise.

Synchronization: If try_lock_shared() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.

Throws: Nothing.

The expression m.try_lock_shared_for(rel_time) shall be well-formed and have the following semantics:

Requires: The calling thread has no ownership of the mutex.

Effects: Attempts to obtain shared lock ownership for the calling thread within the relative timeout ([thread.req.timing]) specified by rel_time. If the time specified by rel_time is less than or equal to rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock_shared()). The function shall return within the timeout specified by rel_time only if it has obtained shared ownership of the mutex object. [ Note: As with try_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.

Return type: bool.

Returns: true if the shared lock was acquired, false otherwise.

Synchronization: If try_lock_shared_for() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.

Throws: Timeout-related exceptions ([thread.req.timing]).

The expression m.try_lock_shared_until(abs_time) shall be well-formed and have the following semantics:

Requires: The calling thread has no ownership of the mutex.

Effects: The function attempts to obtain shared ownership of the mutex. If abs_time has already passed, the function attempts to obtain shared ownership without blocking (as if by calling try_lock_shared()). The function shall return before the absolute timeout ([thread.req.timing]) specified by abs_time only if it has obtained shared ownership of the mutex object. [ Note: As with try_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.

Return type: bool.

Returns: true if the shared lock was acquired, false otherwise.

Synchronization: If try_lock_shared_until() returns true, prior unlock() operations on the same object synchronize with ([intro.multithread]) this operation.

Throws: Timeout-related exceptions ([thread.req.timing]).

30.4.1.4.1 Class shared_timed_mutex [thread.sharedtimedmutex.class]

namespace std {
  class shared_timed_mutex {
  public:
    shared_timed_mutex();
    ~shared_timed_mutex();
  
    shared_timed_mutex(const shared_timed_mutex&) = delete;
    shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
  
    // Exclusive ownership
    void lock();  // blocking
    bool try_lock();
    template <class Rep, class Period>
      bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
      bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock();
  
    // Shared ownership
    void lock_shared();  // blocking
    bool try_lock_shared();
    template <class Rep, class Period>
      bool
      try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
    template <class Clock, class Duration>
      bool
      try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
    void unlock_shared();
  };
}

The class shared_timed_mutex provides a non-recursive mutex with shared ownership semantics.

The class shared_timed_mutex shall satisfy all of the SharedTimedMutex requirements ([thread.sharedtimedmutex.requirements]). It shall be a standard-layout class (Clause [class]).

The behavior of a program is undefined if:

  • it destroys a shared_timed_mutex object owned by any thread,

  • a thread attempts to recursively gain any ownership of a shared_timed_mutex, or

  • a thread terminates while possessing any ownership of a shared_timed_mutex.