我正在阅读APUE,我对第11章的线程同步感到困惑。下面是一段代码片段。
#define NHASH 29
#define HASH(fp) (((unsigned long)fp)%NHASH)
struct foo *fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;
struct foo {
int f_count;
pthread_mutex_t f_lock;
struct foo *f_next; /* protected by hashlock */
int f_id;
/* ... more stuff here ... */
};
struct foo *
foo_alloc(void) /* allocate the object */
{
struct foo *fp;
int idx;
if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp->f_count = 1;
if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
free(fp);
return(NULL);
}
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
fp->f_next = fh[idx];
fh[idx] = fp;
pthread_mutex_lock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
/* ... continue initialization ... */
pthread_mutex_unlock(&fp->f_lock);
}
return(fp);
}
我的怀疑是:
为什么将pthread_mutex_lock(&fp->f_lock)
放在pthread_mutex_unlock(&hashlock)
之前?我可以把它放在后面吗?
由于fp
是本地变量,可以同时删除pthread_mutex_lock(&fp->f_lock)
和pthread_mutex_unlock(&fp->f_lock)
吗?
答案 0 :(得分:0)
我猜这是第二个线程循环创建的对象,用它们做些什么。在这种情况下:
不,因为循环线程可能会在初始化之前访问新创建的对象。
不,因为循环线程可能会访问新创建的对象半初始化。
答案 1 :(得分:0)
不,因为pthread_mutex_lock(&hashlock)
之后的操作会将新创建的结构公开给其他线程,方法是将其添加到fh
列表中。在保持哈希锁的同时,没有人可以访问该变量;一旦释放了hashlock,其他线程就可以通过哈希访问它,但是锁定fp_>f_lock
互斥锁会阻止任何人弄乱fp
。
没有写入的代码。如果整个结构初始化除了散列,那么你可以不锁定fp->f_lock
互斥锁;在完成之前,您将锁定hashlock,将新分配的项挂钩到哈希表中,然后释放hashlock,这样你就会安全。如果在将结构添加到哈希表后需要任何独占访问权限,则必须获取其互斥锁。它的编写方式是互斥的非等待获取;没有其他进程可以访问变量。
if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp->f_count = 1;
if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
free(fp);
return(NULL);
}
idx = HASH(fp);
/* ... complete initialization except for adding to hash table ... */
pthread_mutex_lock(&hashlock);
fp->f_next = fh[idx];
fh[idx] = fp;
pthread_mutex_unlock(&hashlock);
}
因此,所做的事情背后有逻辑;这是对的。