【问题标题】:Check if pthread_mutex is initialized检查 pthread_mutex 是否已初始化
【发布时间】:2014-08-19 13:06:45
【问题描述】:

使用 pthread 必须在获得锁之前对任何互斥体调用 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++),我想避免最大程度的错误使用。 IE。客户端可能会初始化两次创建的对象,可能会在正确初始化之前将对象传递给其他函数等。

目前对象中有一个附加标志,用于标记互斥锁是否已初始化,我想知道这是否真的有必要。

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

更新: 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;
}

有时它会死锁,有时它打印正常。 .....

【问题讨论】:

  • 与其尝试检查互斥锁是否已初始化,不如去了解它。

标签: c linux pthreads posix


【解决方案1】:

至少要回答这部分问题,

查看用于静态互斥体初始化的宏 PTHREAD_MUTEX_INITIALIZER 的扩展,它只是扩展为一个所有成员都设置为 0 的结构。我可以假设如果不再需要调用 mutex_destroy,则不需要调用 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,因此这样做没有害处。充其量它会释放任何不再需要的资源,并且可能会破坏互斥锁的值以将其标记为已销毁,或者在最坏的情况下,它什么也不做。

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

【讨论】:

    【解决方案2】:

    不,您无法检测到这一点。 EINVAL 可能为未初始化的互斥体返回,但不一定。

    另外 POSIX 状态:

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

    所以你不应该这样做。

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

    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    

    【讨论】:

    • PTHREAD_MUTEX_INITIALIZER 如果您需要默认类型的互斥锁,则可以使用。对于其他类型,您可能需要附带的 pthread_once_t 对象和 pthread_once 调用来初始化它,除非只有一个线程能够在创建互斥锁时访问资源(例如,动态分配的对象仅放置在初始化后其他线程可见的索引)。
    • 我遇到了同样的问题,我很好奇,如果PTHREAD_MUTEX_INITIALIZER 可以用于初始化默认类型的互斥锁,为什么函数pthread_mutex_init() 是库的一部分?它是否适用于动态分配的互斥锁?
    • 是的,对于具有非默认属性的互斥锁。
    猜你喜欢
    • 1970-01-01
    • 2011-10-12
    • 2015-05-23
    • 2019-01-25
    • 1970-01-01
    • 2017-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多