5
votes

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.

4
According to this document, "Page 1163 § 30.4.1.2, The error conditions for error codes, if any, reported by member functions of the mutex types shall be: — resource_unavailable_try_again; operation_not_permitted ... device_or_resoSteve
Good question, by the way.Steve
@Steve I don't get it. According to the document, 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. " But mutex constructor can not throw.John Z. Li
@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. That makes it look like this question is unanswered.MSalters
Note that there is no requirement that std::mutex must be implemented by using POSIX threads, i.e., pthread library.Daniel Langr

4 Answers

2
votes

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.

2
votes

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.

2
votes

According to C++17 specification:

33.4.3.2 Mutex types [thread.mutex.requirements.mutex]

  1. 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]

  1. 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.

  2. 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.

1
votes

If you sum it all up this leads to the fact that pthread_mutex_init cannot be called in the std::mutex constructor. There does not need to be a one to one mapping for the construction/initialization. On the contrary!