【发布时间】:2019-04-09 22:29:05
【问题描述】:
调用 pthread_cond_signal 的线程在释放信号线程之前重新获取互斥锁。
下面的代码显示了当前问题的一个简单示例。主线程将持有锁,创建工作线程,然后进入一个在数据进入时打印数据的循环。它通过条件变量发出运行信号。
工作线程将进入一个循环,生成数据,获取锁,写入数据,然后向主线程发出信号。
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int data = 0;
void *thread(void *arg) {
int length = *(int *) arg;
for (int i = 0; i < length; i++) {
// Do some work
pthread_mutex_lock(&lock);
data = i;
fprintf(stdout, "Writing\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
pthread_exit(0);
}
int main(int argc, const char *argv[]) {
pthread_t worker;
int length = 4;
pthread_mutex_lock(&lock);
pthread_create(&worker, 0, thread, &length);
for (int i = 0; i < length; i++) {
fprintf(stdout, "Waiting\n");
pthread_cond_wait(&cond, &lock);
fprintf(stdout, "read data: %d\n", data);
}
pthread_mutex_unlock(&lock);
pthread_join(worker, NULL);
return 0;
}
这将给出以下输出:
Waiting
Writing
Writing
Writing
Writing
read data: 3
Waiting
预期行为: 主线程持有互斥锁,只有在等待时才释放它。然后,工作线程将写入其数据并向主线程发出信号。主线程将立即锁定互斥量 on 信号,然后读取数据并返回等待,释放互斥量。与此同时,工作线程将完成它的工作并一直等待,直到主线程再次等待写入其数据并发出信号。
相反,工作线程似乎在调用信号后立即获得互斥锁,很少让主线程获得访问权限。如果我在工作线程中放置一个睡眠来代替// Do some work,那么它将给出预期的输出。
【问题讨论】:
-
为什么会出乎意料?
-
@immibis 由于主线程正在等待 cond,我预计它会在收到信号后立即停止被阻塞并拥有互斥锁的优先权。相反,工作线程能够在主线程之前到达互斥锁。
-
你应该使用sched_yield()而不是睡觉。
-
@Cyrusc 显然,与工作线程再次获取互斥锁相比,解除阻塞主线程所需的时间更长。当事情是多线程的时,您无法选择它们发生的顺序!