我读到了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_unlock
和pthread_mutex_destroy
之间存在争用条件: B线程可以在pthread_mutex_lock
之间调用pthread_mutex_unlock
和{{1>}在线程中会导致未定义的行为(“尝试销毁锁定的互斥锁导致未定义的行为”)。
我是对的吗?如果我是对的,那么,如何使其正常工作或如何使用pthread_mutex_destroy
安全正确地销毁Linux中的互斥锁?
答案 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
释放对象的内存也是错误的。我们可以通过确保在释放其内存之前找不到该对象来避免此问题。我们将在后面的示例中看到如何执行此操作。