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

con*_*ong 6 c linux mutex pthreads race-condition

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在和foo_rele之间存在竞争条件:B 线程可以在A 线程之间和中调用,这将导致未定义的行为(“尝试销毁锁定的互斥量会导致未定义的行为”)。pthread_mutex_unlockpthread_mutex_destroypthread_mutex_lockpthread_mutex_unlockpthread_mutex_destroy

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

Mic*_*urr 3

POSIX 规范pthread_mutex_destroy()说:

\n\n
\n

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

\n
\n\n

这意味着,如果线程 B在 then语句的子句pthread_mutex_unlock()中调用,则线程 A 的调用是安全的,因为它只能在线程 B 的调用解锁互斥体之后才能到达那里。elseiffoo_rele()pthread_mutex_destroy()pthread_mutex_unlock()

\n\n

所有这些都假设引用计数是正确的,这样在线程 A 解锁互斥锁后,其他线程无法将计数从 0 增加到 1。换句话说,当引用计数降至 0 时,不可能有另一个线程可能调用foo_hold().

\n\n

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

\n\n
\n

在此示例中,我们忽略了线程 \xef\xac\x81 在调用之前如何获取对象foo_hold。即使引用计数为零,foo_rele如果另一个线程在调用foo_hold. 我们可以通过确保在释放内存之前可以找到该对象\xe2\x80\x99来避免这个问题。我们\xe2\x80\x99将在下面的示例中看到如何执行此操作。

\n
\n