2017-03-15 45 views
0

确保在多线程环境中仅对堆栈分配的pthread_mutex_t对象进行一次初始化的建议/标准方法是什么?如何确保共享堆栈分配pthread_mutex_t的单个初始化? (C++)

pthread_mutex_init()手册页说:

试图初始化在 不确定的行为已初始化互斥结果。

我有一个.cpp文件被编译到共享库。此文件的简化是:

#include <pthread.h> 

static pthread_mutex_t g_mutex; 

int initialize() 
{ 
    pthread_mutex_init(&g_mutex, NULL); 
    pthread_mutex_lock(&g_mutex); 
    // Do init stuff. 
    pthread_mutex_unlock(&g_mutex); 
    return 0; 
} 

initialize()可以在多线程环境中调用。因此,如上所述,pthread_mutex_init()可能会在同一个对象上被调用多次,这是未定义的行为。所以这需要线程安全......通过使用另一个互斥体。但是,那么谁是以线程安全的方式初始化这个互斥锁呢?

在全球范围内(即与pthread_mutex_t对象声明相同的范围)调用pthread_mutex_init()是否合法?是否被认为是这种情况的“正确”解决方案?

#include <pthread.h> 

static pthread_mutex_t g_mutex; 
static int g_res = pthread_mutex_init(&g_mutex, NULL); 

int initialize() 
{ 
    // g_mutex already initialized (?) so no need to do so here. 
    pthread_mutex_lock(&g_mutex); 
    // Do init stuff. 
    pthread_mutex_unlock(&g_mutex); 
    return 0; 
} 

我已经试过

我编译和运行第二个代码块,这两者的成功。

但是我还是想问的社区,因为我有点不清楚停靠全球范围内pthread_mutex_init()功能的合法性,我想,以确保执行不只是出现的,因为不确定的工作行为。

回答

1

是合法的,在全球范围内调用pthread_mutex_init()(即在同一范围为pthread_mutex_t对象的声明)作为下方,这被认为是“正确的”解决方案?

它在C中不合法,但在C++中没有问题。既然你初始化具有默认属性的互斥体,然而,这将是最好使用初始化宏:

static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 
+0

我也读了关于'PTHREAD_MUTEX_INITIALIZER',但那么提示问题_什么,如果默认属性不会做?_。我也很好奇,会发生什么在C编译器中的“解决方案”代码?是一个编译或运行时错误吗? – StoneThrow

+0

@StoneThrow,建议的解决方案将被符合C编译器拒绝 –

+0

“但它在C++中没有问题”...所以我猜想在C++中,如果默认属性不行,那么静态声明一个'pthread_mutexattr_t'并将其作为参数传递给'pthread_mutex_init()'...的全局函数是可以接受的。我很好奇这种情况在C中如何解决。也许我会问一个单独的问题。 – StoneThrow

1
static int g_res = pthread_mutex_init(&g_mutex, NULL); 

是在C++代码罚款,但在C代码不工作(是的,你的代码是纯C++,但有人会尝试在C ...)

对于C(或替代在每the POSIX standard C++):

...

在默认互斥属性是适当的情况下,宏 PTHREAD_MUTEX_INITIALIZER可用于初始化互斥。 效果应该等同于通过调用 pthread_mutex_init()并将参数attr指定为NULL来动态初始化。 ...

像这样:

static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 
+0

同样的问题,以@JohnBollinger: \t 我读到PTHREAD_MUTEX_INITIALIZER为好,但随后那会提示这个问题,如果默认属性不行?我也很好奇,C编译器中的“解决方案”代码会发生什么?这是一个编译或运行时错误? – StoneThrow

+1

@StoneThrow在这种情况下,我会做的是将我的互斥体初始化代码放在我知道的地方*它只能被调用一次(例如,共享对象初始化函数,当共享对象被加载时只运行一次,或者我会使用一个用'PTHREAD_MUTEX_INITIALIZER'初始化的静态互斥体来保护我更复杂的初始化代码。FWIW,Linux提供了可用于初始化其他非默认互斥体的扩展,例如'PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP'。请参见http:// elias .rhi.hi.is/libc/Mutexes.html –