c++ - 在 C++ 中销毁 pthread 互斥锁和去初始化顺序

标签 c++ pthreads mutex

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包括这个措辞:

In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes. The effect shall be equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL, except that no error checks are performed.

这表明如果 pthread_mutex_destroy() 预期在使用 pthread_mutex_init() 初始化的互斥量上调用,那么它应该在使用 初始化的互斥量上调用PTHREAD_MUTEX_INITIALIZER 也是如此。

但是,在网上和 Stack Overflow 上搜索时,我发现对于是否需要它存在分歧。例如,here有人引用了一本关于 Linux 开发的书:

It is not necessary to call pthread_mutex_destroy() on a mutex that was statically initialized using PTHREAD_MUTEX_INITIALIZER.

另一方面,在this thread有人认为明确销毁这样的互斥体实际上是必需的。

我还看到它争辩说在这种情况下没有必要清理互斥锁,无论它们是如何初始化的,因为资源无论如何都会被回收。 (这可能与“首次使用时构造并故意泄漏内存”成语背后的逻辑相同,有时用于单例和其他具有静态存储持续时间的对象。)

我发现了很多涉及该主题的其他话题,对于是否/如何销毁互斥量存在各种意见。我还要提到的是,我相信我已经看到来自可靠来源的生产代码,这些代码使用 PTHREAD_MUTEX_INITIALIZER 初始化互斥量并且从不销毁它们。

出于尽职调查的目的,我在这里详细介绍了一些细节,但我的问题(我认为)相当简单。拥有从初始化到程序生命周期结束的互斥量是很有用的。我怀疑不清理此类互斥锁不会造成任何问题,但这种方法让我很烦恼。尽管有人说不需要清理使用 PTHREAD_MUTEX_INITIALIZER 初始化的互斥体,但这似乎与文档和其他人提出的各种声明相悖。

总而言之,是否有一种安全合理的方法来管理旨在在程序生命周期结束之前可用的 pthread 互斥量?这里有没有我在搜索中偶然发现的标准最佳实践?

最佳答案

因为用PTHREAD_MUTEX_INITIALIZER初始化等同于调用pthread_mutex_init,所以调用pthread_mutex_destroy来销毁这样一个互斥体是可以的。

但是,调用pthread_mutex_destroy不是必需的;资源将在程序退出时由操作系统回收。由于它是一个具有普通析构函数的对象,它不会在程序退出时作为静态清理的一部分被销毁,因此在程序结束之前都可以安全使用。

关于c++ - 在 C++ 中销毁 pthread 互斥锁和去初始化顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59079489/

相关文章:

c++ - 使用CodeBlocks编译64位DLL会导致链接器错误

c - pthread_join() 混合线程输出

c - 在所有线程上读取相同的结构

c - 将指向 void* 的指针传递给 pthread_join 的目的是什么?

hashmap - 戈朗 : Best way to read from a hashmap w/mutex

linux - 我们可以在启动期间在设备驱动程序等中使用互斥量吗?

c++ - 怎么可能锁定 GMutex 两次?

c++ - 检查链接列表中的重复项

C++向下转换以撤消函数覆盖

c++ - 我可以阻止 future 的开发人员使对象可构造吗?