如何使用 pthread_mutex_destroy 安全正确地销毁 Linux 中的互斥量?
How to safely and correctly destroy a mutex in Linux using pthread_mutex_destroy?
我读过 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);
}
}
在foo_rele
中,pthread_mutex_unlock
和pthread_mutex_destroy
之间存在竞争条件:B线程可以调用pthread_mutex_lock
中的 pthread_mutex_unlock
和 pthread_mutex_destroy
线程 将导致未定义的行为 ("Attempting to destroy a locked mutex results in undefined behavior")。
我说得对吗?如果我是对的,那么,如何让它正常工作或如何使用 pthread_mutex_destroy
?
安全正确地销毁 Linux 中的互斥量
pthread_mutex_destroy()
的 POSIX 规范说:
It shall be safe to destroy an initialized mutex that is unlocked.
这意味着如果线程 B 在 foo_rele()
中的 if
语句的 else
子句中调用 pthread_mutex_unlock()
那么线程 A 调用 [=10 是安全的=] 因为它只能在线程 B 的 pthread_mutex_unlock()
调用解锁了互斥体后到达那里。
所有这些都假设引用计数是正确的,这样在线程 A 解锁互斥锁后,其他线程无法从 0 -> 1 递增计数。换句话说,在引用计数下降到 0 时,不可能有另一个线程可能调用 foo_hold()
.
APUE 在示例代码之后的解释中提到了这一点:
In this example, we have ignored how threads find an object before calling foo_hold
. Even though the reference count is zero, it would be a mistake for foo_rele
to free the object’s memory if another thread is blocked on the mutex in a call to foo_hold
. We can avoid this problem by ensuring that the object can’t be found before freeing its memory. We’ll see how to do this in the examples that follow.
我读过 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);
}
}
在foo_rele
中,pthread_mutex_unlock
和pthread_mutex_destroy
之间存在竞争条件:B线程可以调用pthread_mutex_lock
中的 pthread_mutex_unlock
和 pthread_mutex_destroy
线程 将导致未定义的行为 ("Attempting to destroy a locked mutex results in undefined behavior")。
我说得对吗?如果我是对的,那么,如何让它正常工作或如何使用 pthread_mutex_destroy
?
pthread_mutex_destroy()
的 POSIX 规范说:
It shall be safe to destroy an initialized mutex that is unlocked.
这意味着如果线程 B 在 foo_rele()
中的 if
语句的 else
子句中调用 pthread_mutex_unlock()
那么线程 A 调用 [=10 是安全的=] 因为它只能在线程 B 的 pthread_mutex_unlock()
调用解锁了互斥体后到达那里。
所有这些都假设引用计数是正确的,这样在线程 A 解锁互斥锁后,其他线程无法从 0 -> 1 递增计数。换句话说,在引用计数下降到 0 时,不可能有另一个线程可能调用 foo_hold()
.
APUE 在示例代码之后的解释中提到了这一点:
In this example, we have ignored how threads find an object before calling
foo_hold
. Even though the reference count is zero, it would be a mistake forfoo_rele
to free the object’s memory if another thread is blocked on the mutex in a call tofoo_hold
. We can avoid this problem by ensuring that the object can’t be found before freeing its memory. We’ll see how to do this in the examples that follow.