如何使用pthread_mutex_destroy安全正确地销毁Linux中的互斥锁?

时间:2017-09-21 13:28:43

标签: c linux pthreads mutex race-condition

我读到了APUE 3rd,11.6.1互斥体,本章中有关于锁定和解锁互斥锁的示例:

struct foo {
    int             f_count;
    pthread_mutex_t f_lock;
    int             f_id;
    /* ... more stuff here ... */
};

struct foo *
foo_alloc(int id) /* allocate the object */
{
    struct foo *fp;

    if ((fp = malloc(sizeof(struct foo))) != NULL) {
        fp->f_count = 1;
        fp->f_id = id;
        if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
            free(fp);
            return(NULL);
        }
        /* ... continue initialization ... */
    }
    return(fp);
}

void
foo_hold(struct foo *fp) /* add a reference to the object */
{
    pthread_mutex_lock(&fp->f_lock);
    fp->f_count++;
    pthread_mutex_unlock(&fp->f_lock);
}

void
foo_rele(struct foo *fp) /* release a reference to the object */
{
    pthread_mutex_lock(&fp->f_lock);
    if (--fp->f_count == 0) { /* last reference */
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    } else {
        pthread_mutex_unlock(&fp->f_lock);
    }
}

foo_rele中,pthread_mutex_unlockpthread_mutex_destroy之间存在争用条件: B线程可以在pthread_mutex_lock之间调用pthread_mutex_unlock和{{1>}在线程中会导致未定义的行为(“尝试销毁锁定的互斥锁导致未定义的行为”)。

我是对的吗?如果我是对的,那么,如何使其正常工作或如何使用pthread_mutex_destroy安全正确地销毁Linux中的互斥锁?

1 个答案:

答案 0 :(得分:1)

pthread_mutex_destroy()的POSIX规范说:

  

销毁已解锁的初始化互斥锁应该是安全的。

这意味着如果线程B在pthread_mutex_unlock()中的else语句的if子句中调用foo_rele(),则线程A可以安全地调用pthread_mutex_destroy() {1}}因为它只能在线程B的pthread_mutex_unlock()电话解锁互斥锁之后才能到达。

所有这一切都假设引用计数是正确的,这样一些其他线程不能从0增加计数 - >线程A解锁互斥锁后1。换句话说,在refcount降为0的时刻,可能不是另一个可能调用foo_hold()的线程。

APUE在示例代码后面的解释中提到了这一点:

  

在这个例子中,我们忽略了线程在调用foo_hold之前如何找到一个对象。即使引用计数为零,如果在foo_rele的调用中另一个线程在互斥锁上被阻塞,foo_hold释放对象的内存也是错误的。我们可以通过确保在释放其内存之前找不到该对象来避免此问题。我们将在后面的示例中看到如何执行此操作。