我正在读史蒂文斯的书:apue。 2e.我遇到了一个关于互斥量的问题。
我们先看一段代码:(以下代码来自apue 2e的图11.10)
#include <stdlib.h>
#include <pthread.h>
struct foo {
int f_count;
pthread_mutex_t f_lock;
/* ... more stuff here ... */
};
struct foo *
foo_alloc(void) /* allocate the object */
{
struct foo *fp;
if((fp = malloc(sizeof(struct foo))) != NULL){
fp->f_count = 1;
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); /* step 1 */
pthread_mutex_destroy(&fp->f_lock); /* step 2 */
free(fp);
}else{
pthread_mutex_unlock(&fp->f_lock);
}
}
假设我们有两个线程:thread1 和 thread2。 thread1 现在正在运行。
它调用函数foo_rele并完成了步骤1的执行(见上文), 并准备执行step2。
然而,此时发生了上下文切换。线程2开始执行。
thread2 锁定锁 fp->f_lock 然后执行某些操作。但在thread2解锁之前,又发生了上下文切换。
线程2停止执行,线程1开始执行。 thread1 破坏了锁,我们都知道会产生错误。
所以,我的问题是:上面提到的情况有可能发生吗? 我们如何避免它?是否有任何接口(interface)(API)可以自动解锁和销毁互斥锁?
最佳答案
我同意 usr (+1),设计是错误的。
一般来说,在一个线程可以销毁任何东西之前,它必须确定所有其他线程都已完成对它的使用。这需要某种其他形式的线程间同步。您需要的是一种方式,线程 1 可以告诉线程 2 资源需要被释放,并且线程 2 确认这一点,以便线程 1 可以调用 foo_rele() 并确定线程 2 不会尝试使用 fp以后再。或者,线程 2 告诉线程 1 它不再需要 fp,结果线程 1 调用 foo_rele()。
这可以通过多种方式完成。一种是线程1在锁的保护下设置一个标志,然后等待线程2退出。与此同时,线程 2 最终看到了该标志,然后退出。这会释放线程 1,然后线程 1 会调用 foo_rele()。另一种方法是通过管道传递消息(我首选的线程间同步方法);类似于线程 1 -> 线程 2,“请停止使用 fp”:线程 2 -> 线程 1,“好的”(当然,基于枚举的更好定义的消息集是可取的,但你明白我的意思) 。
永远不可能有线程 1 调用 foo_rele() 而线程 2 要么知道它永远不会再接触 fp 要么线程 2 已经退出。
关于c - 如何以原子方式解锁和销毁互斥体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18431722/