我已经编写了一些程序来尝试pthread条件等待。 但问题是,不能保证发出的信号会被捕获,从而线程失去唤醒。我该如何解决这个问题?
#include<stdio.h>
#include<pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_func1(void* arg){
printf("thread1 started\n");
pthread_mutex_lock(&mutex);
printf("thread1: signalling\n");
pthread_cond_signal(&cond);
printf("thread1: signalled\n");
pthread_mutex_unlock(&mutex);
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
pthread_cond_wait(&cond, &mutex);
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
int main(int argc, char** argv){
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
return 0;
}
以下是run:
的输出thread1 started
thread1: signalling
thread2 started
thread2: waiting for signal..
thread1: signalled
thread1: exiting
// nothing happens now; where is the signal??
这是另一个(有效):
thread2 started
thread2: waiting for signal..
thread1 started
thread1: signalling
thread1: signalled
thread1: exiting
thread2: signal received
thread2: exiting
// program successfully exits
我现在不关心任何关键部分,所以我没有使用任何锁。
如何确保每次运行都能正常运行?
编辑:我根据下面的答案编辑了代码。我添加了初始化器和锁。我发布的原始代码是here。
答案 0 :(得分:2)
正如您所注意到的,线程1可能会在线程2调用pthread_cond_wait()
之前发出条件变量的信号。条件变量不记得&#34;已经发出信号,所以唤醒将会丢失。因此,您需要使用某种变量来确定线程2是否需要等待。
int signalled = 0;
void *thread_func1(void* arg){
printf("thread1 started\n");
pthread_mutex_lock(&mutex);
printf("thread1: signalling\n");
signalled = 1;
pthread_cond_signal(&cond);
printf("thread1: signalled\n");
pthread_mutex_unlock(&mutex);
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
if(!signalled) {
pthread_cond_wait(&cond, &mutex);
}
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
但是,此代码仍然不正确。 pthreads规范表明&#34;虚假的唤醒&#34;可能在条件变量上发生。这意味着即使没有人调用pthread_cond_wait()
或pthread_cond_signal()
,pthread_cond_broadcast()
也可能会返回。因此,您需要在循环中检查标志,而不是仅检查一次:
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
while(!signalled) {
pthread_cond_wait(&cond, &mutex);
}
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
更新:组合条件变量和计数器功能的另一种方法是使用信号量。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem;
void *thread_func1(void* arg){
printf("thread1 started\n");
printf("thread1: signalling\n");
sem_post(&sem);
printf("thread1: signalled\n");
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
printf("thread2: waiting for signal..\n");
sem_wait(&sem);
printf("thread2: signal received\n");
printf("thread2: exiting\n");
pthread_exit(0);
}
int main(int argc, char** argv){
pthread_t thread1, thread2;
sem_init(&sem);
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
sem_destroy(&sem);
return 0;
}
答案 1 :(得分:0)
对于初学者,您的代码会错过初始化mutex
和cond
。
为此,至少要这样做:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
传递给pthread_cond_wait()
的互斥锁也应 锁定。当函数返回时 被锁定。
更新:
您的代码介绍了一场比赛。也就是说:如果线程1在线程2等待信号之前发出信号,则线程2将永远等待,这很可能发生在您显示的第一条跟踪中。