The pthread_mutex_init()
function returns a non-zero value when it fails to initialize the mutex, while the std::mutex
class in C++11 has a constructor of noexcept
.
Say one chooses to implement a C++ mutex class on top of pthreads mutex. He wraps a pthread mutex inside the class and tries to initialize it by calling pthread_mutex_init() in constructor. If the function call returns a value other than zero, meaning error, the error can't be reported immediately since the constructor can not throw. One alternative is to throw an exception until the lock method is actually called on the mutex. But this approach just seems wrong.
Is there another way to do this, employing some clever tricks to guarantee that initializing a mutex always succeed?
Update: I am going to answer my own question on this one. According to language standard, in 30.4.1.3 pge 1163, it says ". If initialization of an object of a mutex type fails, an exception of type system_error shall be thrown. "
And a function of noexcept can throw inside the function body, it is just the caller can not catch the exception. If an exception is thrown inside a noexcept function, std::terminate will be called.
By design, std::mutex is not movable nor copyable. This means that a class A holding a mutex won't receive a default move constructor.
std::mutex The mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.
std::mutex::mutexmutex objects cannot be copied/moved (both the copy constructor and assignment operator are deleted for this type).
A constructor is a member function with the same name as its class. For example: class X { public: X(); // constructor for class X }; Constructors are used to create, and can initialize, objects of their class type.
The pthread_mutex_init () function returns a non-zero value when it fails to initialize the mutex, while the std::mutex class in C++11 has a constructor of noexcept. Say one chooses to implement a C++ mutex class on top of pthreads mutex.
If initialization of an object of a mutex type fails, an exception of type system_error shall be thrown. " But mutex constructor can not throw. @JohnZ.Li: It's OK to answer your own question, and if nobody else comes up with a better answer, you can even accept it. Please However, please don't put the answer inside your question.
(since C++11) The mutex class is a synchronization primitive that can be used to protect shared data from being simultaneously accessed by multiple threads.
In Windows, you have to create a named mutex and then open a new handle based on that name, for example, intended to be used in a new thread/process and std::mutex never creates named objects. So even if there was a copy constructor, it would be impossible to implement it.
The constructor of std::mutex
needs to be constexpr
(so that a global std::mutex
can be statically initialized and used in constructors of other global objects), and therefore cannot call pthread_mutex_init
(or similar functions) at all.
Instead, it needs to use PTHREAD_MUTEX_INITIALIZER
or equivalent (e.g., SRWLOCK_INIT
on Windows) to statically initialize the mutex.
It seems to me that errors from pthread_mutex_init
are simply ignored in libstdc++:
https://github.com/psp2sdk/libs/blob/master/include/c%2B%2B/bits/gthr-posix.h#L732
where __gthread_mutex_init_function
is via macro __GTHREAD_MUTEX_INIT_FUNCTION
invoked here
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/std_mutex.h#L75
that is in std::mutex
constructor via its base class.
UPDATE
One can initialize Pthread mutex with PTHREAD_MUTEX_INITIALIZER
and then
no error checks are performed
I guess error handling can be postponed to locking functions; quoting from documentation of pthread_mutex_lock
and pthread_mutex_trylock
ERRORS section:
EINVAL
The value specified by mutex does not refer to an initialized mutex object.
This implies that errors in pthread_mutex_init
can be safely ignored in std::mutex
constructor.
According to C++17 specification:
33.4.3.2 Mutex types [thread.mutex.requirements.mutex]
- The mutex types shall be DefaultConstructible and Destructible. If initialization of an object of a mutex type fails, an exception of type system_error shall be thrown. The mutex types shall not be copyable or movable.
So mutex type
may throw an exception not std::mutex
. std::mutex
has noexcept
, but std::recursive_mutex
does not and they are both mutex types
:
33.4.3.2.1 Class mutex [thread.mutex.class]
constexpr mutex() noexcept;
33.4.3.2.2 Class recursive_mutex [thread.mutex.recursive]
recursive_mutex();
Moreover:
20.5.5.12 Restrictions on exception handling [res.on.exception.handling]
Any of the functions defined in the C++ standard library can report a failure by throwing an exception of a type described in its Throws: paragraph, or of a type derived from a type named in the Throws: paragraph that would be caught by an exception handler for the base type.
Functions defined in the C++ standard library that do not have a Throws: paragraph but do have a potentially throwing exception specification may throw implementation-defined exceptions. Implementations should report errors by throwing exceptions of or derived from the standard exception classes (21.6.3.1, 21.8, 22.2).
There is no Throws paragraph and it does not have potentially throwing exception specification.
So std::mutex
constructor shall never throw an exception or call std::terminate
the same way as any other function from standard library with noexcept
specification on conforming C++ implementation.
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