BFS算法解析:网格信号传播问题与实现
2026/9/13 17:08:55
各类资料学习下载合集
链接:https://pan.quark.cn/s/7c8c391011eb
在上一篇博客中,我们已经初步实现了基于条件变量的生产者-消费者模型。然而,当涉及到多消费者场景时,我们对代码的严谨性提出了更高的要求。本文将详细讲解pthread_cond_wait的正确使用姿势,特别是为什么它必须与while循环结合,以及pthread_cond_signal可能带来的“意外”行为。
我们再次梳理一下生产者和消费者使用条件变量进行协作的基本流程。
pthread_mutex_lock(&mutex),保护公共区。pthread_mutex_unlock(&mutex)。pthread_cond_signal(&cond),告知有新数据了。pthread_mutex_lock(&mutex),准备检查公共区。pthread_cond_wait(&cond, &mutex)。这是一个“三合一”操作:wait函数返回。pthread_mutex_unlock(&mutex)。if到while现在,我们来重点关注消费者线程中的一个关键点:条件判断。在单消费者场景下,我们可能习惯用if (head == NULL)来判断是否需要等待。但在多消费者场景下,这将是灾难性的!
if判断假设我们有多个消费者,代码片段如下:
// 消费者线程函数 (错误示例 - 使用 if)void*consumer_bad(void*arg){while(1){pthread_mutex_lock(&mutex);// 错误!这里使用 if 判断if(head==NULL){pthread_cond_wait(&has_data,&mutex);}// ... (取数据、解锁、消费)// 假设这里会取走 head 指向的数据// ...pthread_mutex_unlock(&mutex);// ...}returnNULL;}问题分析:
head == NULL时,所有消费者都会进入if语句块,并调用pthread_cond_wait阻塞。signal:生产者生产一个数据,并调用pthread_cond_signal(&has_data)。signal的“意外”行为:尽管官方文档说pthread_cond_signal唤醒“至少一个”线程,但在许多 Linux/POSIX 实现中,它实际上可能唤醒所有等待在该条件变量上的线程(或者唤醒多个,数量不确定)。signal唤醒了三个消费者 A、B、C。mutex。假设 A 抢到了锁,它会跳过if语句(因为wait返回时head可能不再为NULL),取出数据并消费。head再次变为NULL(已经被 A 取走了)。但 B 之前已经通过了if (head == NULL)的判断,它不会再次检查条件,而是直接尝试去取数据。head指针,导致程序崩溃或数据损坏!while循环判断为了彻底避免上述问题,我们必须将条件判断放在while循环中:
// 消费者线程函数 (正确示例 - 使用 while)void*consumer(void