检查pthread_mutex是否已初始化

时间:2014-06-28 15:48:40

标签: c linux pthreads posix

使用pthreads必须在获取锁之前在任何互斥锁上调用pthread_mutex_init()。

根据POSIX,锁定未初始化的互斥锁仅定义为具有优先级保护的互斥锁(opengroup : pthread_mutex_lock

根据联机帮助页pthread_mutex_lock.3thr,如果在未经初始化的互斥锁上调用,它应返回EINVAL。 假设可移植性不是问题,编写如下代码是否有效(一个好主意?):

pthread_mutex_t lock;

int ret = pthread_mutex_lock(&lock);
if (ret != 0){  
    if(ret == EINVAL){
        pthread_mutex_init(&lock, NULL);
    } else {
      /* other error */
    }
} 

还有另一种检查pthread_mutex是否已初始化的方法吗?

整个场景是图书馆的一部分(不幸的是政治不是C ++),我想避免最大限度的错误使用。即客户端可以初始化两次创建的对象,可以在正确初始化之前将对象传递给其他函数等。

目前在对象中有一个aditional标志,表示互斥锁是否已经初始化,我很想知道这是否真的有必要。

查看静态互斥量初始化的宏PTHREAD_MUTEX_INITIALIZER的扩展,它只是扩展为一个所有成员都设置为0的结构。 我可以假设,如果不再需要,则不需要调用mutex_destroy,因为ressource本身已被释放(确定没有其他人使用它)?

更新: Jens的回答绝对正确。以下程序产生完全未定义的行为:

int main(int argc, char** argv)
{

pthread_mutex_t lock;
int ret = pthread_mutex_lock(&lock);
if (ret != 0) {
    printf(" ERR : %d %s \n", ret, strerror(ret));
    if (ret == EINVAL) {
        pthread_mutex_init(&lock, NULL);
    }
} else {
    printf(" ok \n");
}
pthread_mutex_unlock(&lock);
return 0;
}

有时会出现僵局,有时会打印出来。 .....

2 个答案:

答案 0 :(得分:4)

不,你无法察觉。可以为未初始化的互斥锁返回EINVAL ,但不一定非。

另外POSIX声明:

  

尝试初始化已初始化的互斥锁导致   未定义的行为。

所以你不应该试试。

最好的方法是完全避免这种情况并正确初始化变量。这应该通过宏PTHREAD_MUTEX_INITIALIZER完成。

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

答案 1 :(得分:0)

至少要回答问题的这一部分,

<块引用>

查看用于静态互斥初始化的宏 PTHREAD_MUTEX_INITIALIZER 的扩展,它只是扩展为一个所有成员都设置为 0 的结构。如果不再需要,我可以假设不需要调用 mutex_destroy,因为资源本身是释放了(确定没有其他人使用它)?

来自 man page 的 pthread_mutex_init

<块引用>

PTHREAD_MUTEX_INITIALIZER 可用于初始化静态分配的互斥锁。除了不执行错误检查外,效果应等同于通过调用 pthread_mutex_init() 并将参数 attr 指定为 NULL 进行动态初始化。

来自 man page for win32 pthread_mutex_init

<块引用>

在 Pthreads-w32 实现中,应用程序仍应在某个时刻调用 pthread_mutex_destroy,以确保释放互斥锁消耗的任何资源。

基于手册页声明静态初始化和动态初始化是等效的这一事实,这使我相信静态初始化的互斥锁在不再使用时应该总是被销毁。在 pthreads 手册页的 win32 版本中明确说明了这一点。此外,销毁使用 PTHREAD_MUTEX_INITIALIZER 分配的互斥锁不会返回错误,它会很高兴地返回 0,因此这样做没有害处。充其量它会释放不再需要的任何资源,并可能毒害互斥锁的值以将其标记为销毁,或者最坏的情况是什么都不做。

总而言之,为了可移植性,我总是会销毁任何已初始化的互斥锁,即使它是使用静态初始化程序完成的。