5

pthread_mutex_init()函数在初始化互斥锁失败时返回一个非零值,而std::mutexC++11 中的类具有noexcept.

假设一个人选择在 pthreads 互斥体之上实现一个 C++ 互斥体类。他在类中包装了一个 pthread 互斥锁,并尝试通过在构造函数中调用 pthread_mutex_init() 来初始化它。如果函数调用返回一个非零值,即错误,由于构造函数不能抛出,所以不能立即报告错误。一种替代方法是在互斥体上实际调用锁定方法之前抛出异常。但这种方法似乎是错误的。

有没有另一种方法来做到这一点,采用一些巧妙的技巧来保证初始化互斥锁总是成功的?

更新:我将在这个问题上回答我自己的问题。根据语言标准,在 30.4.1.3 pge 1163 中,它说“。如果互斥锁类型的对象初始化失败,则应抛出 system_error 类型的异常。”

而noexcept的函数可以在函数体内抛出,只是调用者无法捕捉到异常。如果在 noexcept 函数内抛出异常,则将调用 std::terminate。

4

4 回答 4

3

的构造函数std::mutex需要是constexpr(以便全局std::mutex可以静态初始化并用于其他全局对象的构造函数),因此根本不能调用pthread_mutex_init(或类似函数)。

相反,它需要使用PTHREAD_MUTEX_INITIALIZER或等效(例如,SRWLOCK_INIT在 Windows 上)来静态初始化互斥锁。

于 2018-02-09T19:06:51.710 回答
2

在我看来,pthread_mutex_initlibstdc++ 中的错误只是被忽略了:

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_MUTEX_INITIALIZER可以使用然后初始化 Pthread 互斥锁

不执行错误检查

我猜错误处理可以推迟到锁定功能;引用文档pthread_mutex_lockpthread_mutex_trylock错误部分:

EINVALmutex 指定的值不引用已初始化的互斥对象。

这意味着可以在构造函数pthread_mutex_init中安全地忽略错误。std::mutex

于 2018-02-09T12:54:23.173 回答
2

根据 C++17 规范:

33.4.3.2 互斥体类型 [thread.mutex.requirements.mutex]

  1. 互斥锁类型应为 DefaultConstructible 和 Destructible。如果互斥体类型的对象初始化失败,则应抛出 system_error 类型的异常。互斥锁类型不得复制或移动。

所以mutex type可能不会抛出异常std::mutexstd::mutexnoexcept,但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构造函数永远不会抛出异常或调用与标准库中具有符合 C++ 实现规范std::terminate的任何其他函数相同的方式。noexcept

于 2019-12-03T20:45:13.067 回答
1

如果你总结一下,这会导致pthread_mutex_init无法在std::mutex构造函数中调用的事实。构造/初始化不需要一对一的映射。相反!

于 2018-02-09T11:29:22.347 回答