From CPPReference, it isn't said explicitly that the lock function of std::mutex
won't throw if the lock won't result in a dead lock.
PThread's lock only have a deadlock error. I don't know for window's implementation of thread. I also don't know if they are other implementation of thread used as backend of std::thread
/std::mutex
.
So my question is "Should I write my code as if, some times, for no special reason, a lock may fail?".
I actually need to lock a mutex in some noexcept methods, and I want to be sure that they are noexcept.
The std::mutex::lock()
member function is not declared as noexcept
and from section 30.4.1.2 Mutex types of the c++11 standard (draft n3337), clause 6:
The expression
m.lock()
shall be well-formed and have the following semantics:
- ...
- Throws:
system_error
when an exception is required (30.2.2).- 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.
This implies that any function that uses mutex::lock()
cannot be marked noexcept
, unless that function is capable of handling the exception itself and prevents it from propogating to the caller.
I am unable to comment on the likelihood of these error conditions occuring, but in relation to std::mutex
and resource_deadlock_would_occur
(which might be thrown) it indicates a bug in the code as opposed to a runtime a failure as this error might be raised if a thread attempts to lock a std::mutex
it already owns. From section 30.4.1.2.1 Class mutex, clause 4:
[ Note: A program may deadlock if the thread that owns a mutex object calls lock() on that object. If the implementation can detect the deadlock, a resource_deadlock_would_occur error condition may be observed. —end note ]
By selecting std::mutex
as the lock type the programmer is explicitly stating that an attempt by the same thread to lock a mutex
it already has locked is not possible.
It if is a legal path of execution for a thread to re-lock a mutex
then a std:recursive_mutex
is the more appropriate choice (but changing to a recursive_lock
does not mean the lock()
function is exception free).
On a POSIX system, std::mutex
will probably be implemented using POSIX mutexes, and std::mutex::lock()
will eventually delegate to pthread_mutex_lock()
. Although C++ mutexes are not required to be implemented using POSIX mutexes, the authors of the C++ standard multi-threading seem to have modelled the possible error conditions on the POSIX error conditions, so examining those can be instructive. As user hmjd says, the C++ error conditions permitted for the lock
method are operation_not_permitted
, resource_deadlock_would_occur
and device_or_resource_busy
.
The POSIX error conditions are:
EINVAL
: if a POSIX specific lock-priorty feature is misused, which can never happen if you use only the standard C++ multi-threading facilities. This case might correspond to the operation_not_permitted
C++ error code.EINVAL
: if the mutex has not been initialized, which would correspond to a corrupted std::mutex
object, use of a dangling reference, or some other undefined behaviour that indicates a program bug.EAGAIN
: if the mutex is recursive and the recursion is too deep. That can't happen to a std::mutex
, but could happen for a std::recursive_mutex
. This would seem to correspond to the device_or_resource_busy
error condition.EDEADLK
: if deadlock would occur because of the thread already holds the lock. This would correspond to the resource_deadlock_would_occur
C++ error code, but would indicate a program bug, because a program should not attempt to lock a std::mutex
it already holds a lock on (use a std::recursive_mutex
if you really want to do that).The C++ operation_not_permitted
error code is evidently intended to correspond to the POSIX EPERM
error status. The pthread_mutex_lock()
function never gives this status code. But the POSIX manual page that describes that function also describes the pthread_mutex_unlock()
function, which may given EPERM
if you try to unlock a lock you have not locked. Perhaps the C++ standards authors included operation_not_permitted
by a mistaken reading of the POSIX manual page. As C++ has no concept of lock "permissions", it is hard to see how any correctly constructed and manipulated lock (used in accordance with the C++ standard, without invoking any undefined behaviour) could result in EPERM
and thus operation_not_permitted
.
device_or_resource_busy
is not permitted from C++17, which suggests it never really happens in practice, and its inclusion for C++11 was an error.
To summarize, the only cases in which std::mutex::lock()
could throw an exception indicate program bugs. So it can be reasonable to assume the method "never" throws an exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With