pthread_cond_broadcast问题

在Linux 2.6.30中使用pthreads我试图发送一个单一的信号,这将导致多个线程开始执行。 广播似乎只能通过一个线索接收。 我已经尝试了pthread_cond_signal和pthread cond_broadcast,两者似乎都有相同的行为。 对于pthread_cond_wait中的互斥锁,我已经尝试了常见的互斥锁和单独的(本地)互斥锁,没有明显的区别。

worker_thread(void *p) { // setup stuff here printf("Thread %d ready for action \n", p->thread_no); pthread_cond_wait(p->cond_var, p->mutex); printf("Thread %d off to work \n", p->thread_no); // work stuff } dispatch_thread(void *p) { // setup stuff printf("Wakeup, everyone "); pthread_cond_broadcast(p->cond_var); printf("everyone should be working \n"); // more stuff } main() { pthread_cond_init(cond_var); for (i=0; i!=num_cores; i++) { pthread_create(worker_thread...); } pthread_create(dispatch_thread...); } 

输出:

 Thread 0 ready for action Thread 1 ready for action Thread 2 ready for action Thread 3 ready for action Wakeup, everyone everyone should be working Thread 0 off to work 

发送信号到所有线程的好方法是什么?

首先,你应该在你调用pthread_cond_wait()地方锁定互斥锁。 当你调用pthread_cond_broadcast() ,通常也是一个好主意。

其次,当等待条件为真时,您应该循环调用pthread_cond_wait() 。 虚假的唤醒可能发生,你必须能够处理它们。

最后,您的实际问题是:您正在发送所有线程信号,但其中有些信号发送时尚未等待。 你的主线程和调度线程正在竞争你的工作线程:如果主线程可以启动调度线程,并且调度线程可以在工作线程可以获取互斥量和广播,那么这些工作线程永远不会被唤醒。

在发信号之前,您需要一个同步点,等待信号,直到已知所有线程正在等待信号。 那,或者你可以保持信号,直到你知道所有的线程已被唤醒。

在这种情况下,您可以使用互斥锁来保护睡眠线程的计数。 每个线程抓取互斥锁并增加计数。 如果count与工作线程数相匹配,那么这是增加计数的最后一个线程,所以另一个条件变量的信号共享相同的互斥量到睡眠调度线程,所有线程都准备好了。 线程然后等待原始状态,这会释放互斥锁。

如果当最后一个工作线程在这种情况下发出信号时,调度线程还没有睡眠,它就会发现计数已经与所需的计数相匹配,并且不用担心等待,而是立即在共享条件上广播唤醒工人,都睡着了

无论如何,这里有一些工作源代码,充实了您的示例代码,并包含我的解决方案:

 #include <stdio.h> #include <pthread.h> #include <err.h> static const int num_cores = 8; struct sync { pthread_mutex_t *mutex; pthread_cond_t *cond_var; int thread_no; }; static int sleeping_count = 0; static pthread_cond_t all_sleeping_cond = PTHREAD_COND_INITIALIZER; void * worker_thread(void *p_) { struct sync *p = p_; // setup stuff here pthread_mutex_lock(p->mutex); printf("Thread %d ready for action \n", p->thread_no); sleeping_count += 1; if (sleeping_count >= num_cores) { /* Last worker to go to sleep. */ pthread_cond_signal(&all_sleeping_cond); } int err = pthread_cond_wait(p->cond_var, p->mutex); if (err) warnc(err, "pthread_cond_wait"); printf("Thread %d off to work \n", p->thread_no); pthread_mutex_unlock(p->mutex); // work stuff return NULL; } void * dispatch_thread(void *p_) { struct sync *p = p_; // setup stuff pthread_mutex_lock(p->mutex); while (sleeping_count < num_cores) { pthread_cond_wait(&all_sleeping_cond, p->mutex); } printf("Wakeup, everyone "); int err = pthread_cond_broadcast(p->cond_var); if (err) warnc(err, "pthread_cond_broadcast"); printf("everyone should be working \n"); pthread_mutex_unlock(p->mutex); // more stuff return NULL; } int main(void) { pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER; pthread_t worker[num_cores]; struct sync info[num_cores]; for (int i = 0; i < num_cores; i++) { struct sync *p = &info[i]; p->mutex = &mutex; p->cond_var = &cond_var; p->thread_no = i; pthread_create(&worker[i], NULL, worker_thread, p); } pthread_t dispatcher; struct sync p = {&mutex, &cond_var, num_cores}; pthread_create(&dispatcher, NULL, dispatch_thread, &p); pthread_exit(NULL); /* not reached */ return 0; }