Почему конструктор std::mutex в C++ не бросает?

pthread_mutex_init() функция возвращает ненулевое значение, когда не удается инициализировать мьютекс, в то время как std::mutex класс в C++11 имеет конструктор noexcept,

Скажем, кто-то решил реализовать класс мьютекса C++ поверх мьютекса pthreads. Он оборачивает мьютекс pthread внутри класса и пытается инициализировать его, вызывая pthread_mutex_init() в конструкторе. Если вызов функции возвращает значение, отличное от нуля, что означает ошибку, об ошибке нельзя сразу сообщить, так как конструктор не может выдать. Одна альтернатива - генерировать исключение до тех пор, пока метод блокировки не будет вызван в мьютексе. Но этот подход кажется неправильным.

Есть ли другой способ сделать это, используя некоторые хитрые уловки, чтобы гарантировать, что инициализация мьютекса всегда будет успешной?

Обновление: я собираюсь ответить на свой вопрос по этому вопросу. В соответствии с языковым стандартом в 30.4.1.3 pge 1163 написано: "Если инициализация объекта типа мьютекса не удалась, должно быть сгенерировано исключение типа system_error".

И функция noexcept может бросить внутрь тела функции, просто вызывающая сторона не может поймать исключение. Если исключение выдается внутри функции noexcept, будет вызван std::terminate.

3 ответа

Конструктор std::mutex должно быть constexpr (так что глобальный std::mutex может быть статически инициализирован и использован в конструкторах других глобальных объектов), и поэтому не может вызывать pthread_mutex_init (или аналогичные функции) на всех.

Вместо этого он должен использовать PTHREAD_MUTEX_INITIALIZER или эквивалент (например, SRWLOCK_INIT в Windows) для статической инициализации мьютекса.

Согласно спецификации C++17:

33.4.3.2 Типы мьютексов [thread.mutex.requirements.mutex]

  1. Типы мьютексов должны быть DefaultConstructible и Destructible. Если инициализация объекта типа мьютекса не удалась, должно быть выброшено исключение типа system_error. Типы мьютексов нельзя копировать или перемещать.

Так mutex type может вызвать исключение, а не std::mutex. std::mutex имеет noexcept, но std::recursive_mutex нет, и они оба mutex types:

33.4.3.2.1 Мьютекс класса [thread.mutex.class]

constexpr mutex() noexcept;

33.4.3.2.2 Класс recursive_mutex [thread.mutex.recursive]

recursive_mutex();

Кроме того:

20.5.5.12 Ограничения на обработку исключений [res.on.exception.handling]

  1. Любая из функций, определенных в стандартной библиотеке C++, может сообщать о сбое, генерируя исключение типа, описанного в его параграфе Throws:, или типа, производного от типа, указанного в параграфе Throws:, которое будет перехвачено обработчиком исключений. для базового типа.

  2. Функции, определенные в стандартной библиотеке C++, которые не имеют абзаца Throws:, но имеют спецификацию потенциально вызывающего исключения, могут вызывать исключения, определяемые реализацией. Реализации должны сообщать об ошибках, генерируя исключения или производные от стандартных классов исключений (21.6.3.1, 21.8, 22.2).

Здесь нет параграфа Throws и нет спецификации потенциально генерирующего исключения.

Так std::mutex конструктор никогда не должен вызывать исключение или вызывать std::terminate так же, как и любую другую функцию из стандартной библиотеки с noexcept спецификация соответствующей реализации C++.

Мне кажется, что ошибки от pthread_mutex_init просто игнорируются в libstdC++:

https://github.com/psp2sdk/libs/blob/master/include/c%2B%2B/bits/gthr-posix.h#L732

где __gthread_mutex_init_function через макрос __GTHREAD_MUTEX_INIT_FUNCTION вызывается здесь

https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/std_mutex.h#L75

это в std::mutex конструктор через его базовый класс.


ОБНОВИТЬ

Можно инициализировать мьютекс Pthread с помощью PTHREAD_MUTEX_INITIALIZER а потом

проверка ошибок не выполняется

Я предполагаю, что обработка ошибок может быть отложена до блокировки функций; цитирование из документации pthread_mutex_lock а также pthread_mutex_trylock Раздел ОШИБКИ:

EINVAL Значение, указанное в mutex, не относится к инициализированному объекту mutex.

Это подразумевает, что ошибки в pthread_mutex_init может быть безопасно проигнорировано в std::mutex конструктор.

Если вы подытожите все это, это приведет к тому, что pthread_mutex_init не может быть вызвано в std::mutex конструктор. Для построения / инициализации не требуется однозначного отображения. Напротив!

Другие вопросы по тегам