在 pthreads 中丢失唤醒 [英] Lost wakeups in pthreads
问题描述
我写了一些程序来尝试 pthread 条件等待.但问题是无法保证发出的信号会被捕获,从而导致线程失去唤醒.我该如何解决这个问题?
I've written a little to program to try out pthread conditional waits. But the problem is that there is no guarantee that a signal when sent out will be caught, thereby the thread losing the wakeup. How do I get around this?
#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;
}
这是一个运行的输出:
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
我现在不关心任何类型的临界区,所以我没有使用任何锁.
I'm not concerned about any kind of critical section for now, so I haven't used any locks.
我如何确保每次运行都能正常工作?
How do I ensure this thing works for each run?
我已经按照下面的 alk 回答编辑了代码.我已经添加了初始化程序和锁.我发布的原始代码是这里.
I have edited the code as per alk's answer below. I have added the initializers and locks. The original code I posted is here.
推荐答案
如您所见,线程 1 可能会在线程 2 调用 pthread_cond_wait()
之前发出条件变量的信号.条件变量不会记住"它已发出信号,因此唤醒将丢失.因此,您需要使用某种变量来确定线程 2 是否需要等待.
As you have noticed, thread 1 might signal the condition variable before thread 2 calls pthread_cond_wait()
. The condition variable does not "remember" that it has been signaled, so the wakeup will be lost. Therefore, you need to use some kind of variable to determine whether thread 2 needs to wait.
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 规范指出虚假唤醒"可能发生在条件变量上.这意味着即使没有人调用 pthread_cond_signal()
或 pthread_cond_broadcast()
,pthread_cond_wait()
也可能返回.因此,您需要在循环中检查标志,而不仅仅是一次:
However, this code is still not correct. The pthreads spec states that "spurious wakeups" may occur on condition variables. This means that pthread_cond_wait()
might return even if nobody has called pthread_cond_signal()
or pthread_cond_broadcast()
. Therefore, you need to check the flag in a loop, rather than just once:
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);
}
更新:结合条件变量和计数器功能的另一种方法是使用信号量.
Update: An alternate method to combine the function of a condition variable and a counter is to use a semaphore.
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;
}
这篇关于在 pthreads 中丢失唤醒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!