使用pthread互斥锁似乎很普遍,这种互斥锁要一直存在到程序生命周期的尽头。通常,这些都是使用pthREAD_MUTEX_INITIALIZER
创建的。
这是一个简短但完整的代码示例,显示了我所指的内容:
#include <pthread.h>
#include <iostream>
void log(char const * const message) {
static pthread_mutex_t mutex = pthREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
std::cout << message << std::endl;
pthread_mutex_unlock(&mutex);
}
struct Object final {
Object() { log("Object::Object()"); }
~Object() { log("Object::~Object()"); }
};
Object const object;
int main(int const argc,const char * argv[]) {
log("main()");
// Here the program would enter a main loop,with log() potentially being
// called from multiple threads at various times.
}
输出:
Object::Object()
main()
Object::~Object()
为简洁起见,省略了错误检查和RAII包装。
此示例包括线程安全(至少是意图)日志记录功能,该功能旨在在程序的整个生命周期中使用,包括在对具有静态存储持续时间的对象进行初始化期间(可能不是(在这种情况下))多个翻译单元,这意味着取消初始化顺序可能不确定。
问题在于,没有机会安全地销毁互斥锁,因为在程序生命周期的任何时候都可能需要它。 (实际上,我不打算使用具有静态存储持续时间和非平凡析构函数的对象,但是我仍然有兴趣解决该问题。)
出现的第一个问题是使用pthREAD_MUTEX_INITIALIZER
初始化的互斥是否需要使用pthread_mutex_destroy()
销毁。 documentation的至少某些版本包含以下措辞:
在默认互斥量属性合适的情况下,宏 pthREAD_MUTEX_INITIALIZER可用于初始化互斥锁。的 效果应等效于通过调用进行动态初始化 参数attr的pthread_mutex_init()指定为NULL,除了 没有执行错误检查。
这表明,如果期望在使用pthread_mutex_destroy()
初始化的互斥锁上调用pthread_mutex_init()
,那么也期望在使用pthREAD_MUTEX_INITIALIZER
初始化的互斥锁上调用。{p>
但是,在在线搜索以及Stack Overflow上的内容中,我发现是否需要此信息存在分歧。例如,here某人从有关Linux开发的书中提供了以下报价:
没有必要在一个互斥锁上调用pthread_mutex_destroy() 是使用pthREAD_MUTEX_INITIALIZER静态初始化的。
另一方面,在this thread中,有人指出实际上确实需要销毁这种互斥体。
我也看到它认为,无论如何初始化互斥量,在这种情况下都不必清理互斥量,因为无论如何都会回收资源。 (这可能与有时用于单例和具有静态存储持续时间的其他对象的“首次使用并故意泄漏内存的构造”惯用语背后的逻辑相同。)
我发现了许多其他与主题相关的主题,并对是否/如何消除互斥有多种看法。我还要提到的是,我相信我已经从可靠的来源中看到了生产代码,这些代码使用pthREAD_MUTEX_INITIALIZER
初始化互斥量,并且从未销毁它们。
作为尽职调查的问题,我在这里进行了详细介绍,但是我的问题很简单。具有从初始化到程序生命周期结束时可用的互斥体将很有用。我怀疑不清理此类互斥锁不会造成任何问题,但是这种方法困扰着我。即使有些人说不需要清理使用pthREAD_MUTEX_INITIALIZER
初始化的互斥体,但这似乎与文档以及其他人提出的各种主张背道而驰。
总而言之,是否存在一种安全合理的方法来管理计划在程序生命周期结束之前可用的pthread互斥锁?这里是否有我没有发现的标准最佳实践?