线程安全有界队列push/pop时线程等待异常排查求助
线程安全有界队列死锁问题排查与修复
你的代码存在多个核心逻辑错误,直接导致程序无法正常结束,以下是问题分析和修正方案:
核心错误点
1. 互斥锁使用时机完全错误
- 调用
pthread_cond_wait必须先持有对应的互斥锁,否则属于未定义行为。你的代码在调用pthread_cond_wait前未加锁,直接访问q->count也会引发竞态条件(多个线程同时读写count)。 - 修改队列的操作(添加/删除节点)必须全程在锁保护下,你现在先判断
q->head == NULL再加锁,这期间队列状态可能被其他线程修改,导致逻辑错误。
2. 条件变量的检查逻辑错误
- 虚假唤醒问题:
pthread_cond_wait可能被虚假唤醒(不是因条件满足被signal唤醒),必须用while循环检查条件,而非if。你的queue_pop用if (q->count == 0)判断,会导致虚假唤醒后直接执行后续逻辑,此时队列可能仍为空。 - 唤醒条件判断错误:
- push操作后,只有当队列从空变为非空时(即push前count为0),才需要唤醒等待empty条件的pop线程;你现在只要count!=0就唤醒,属于无效唤醒,还可能浪费资源。
- pop操作后,只有当队列从满变为非满时(即pop前count为size),才需要唤醒等待full条件的push线程;你现在只要count!=size就唤醒,同样是无效唤醒。
3. 队列状态的访问未受锁保护
所有对q->count、q->head、q->tail的读写操作,必须在互斥锁的保护下执行,否则会出现多线程下的数据竞争,导致队列状态混乱。
修正后的代码实现
修正后的queue_push函数
bool queue_push(queue_t *q, void *elem) { if (q == NULL) { return false; } // 先加锁,再检查队列状态 pthread_mutex_lock(&q->mutex); // 用while循环处理队列满的情况,防止虚假唤醒 while (q->count == q->size) { pthread_cond_wait(&q->full, &q->mutex); } // 执行添加节点的逻辑 node_t *new_node = malloc(sizeof(node_t)); if (new_node == NULL) { pthread_mutex_unlock(&q->mutex); return false; } new_node->content = elem; new_node->next = NULL; new_node->prev = q->tail; if (q->head == NULL) { // 队列原本为空 q->head = new_node; q->tail = new_node; } else { q->tail->next = new_node; q->tail = new_node; } q->count++; // 仅当队列从空变为非空时,唤醒等待empty的线程 if (q->count == 1) { pthread_cond_signal(&q->empty); } pthread_mutex_unlock(&q->mutex); return true; }
修正后的queue_pop函数
bool queue_pop(queue_t *q, void **elem) { if (q == NULL || elem == NULL) { return false; } // 先加锁,再检查队列状态 pthread_mutex_lock(&q->mutex); // 用while循环处理队列空的情况,防止虚假唤醒 while (q->count == 0) { pthread_cond_wait(&q->empty, &q->mutex); } // 执行删除节点的逻辑 node_t *del_node = q->head; *elem = del_node->content; if (q->head == q->tail) { // 队列只剩一个节点 q->head = NULL; q->tail = NULL; } else { q->head = q->head->next; q->head->prev = NULL; } free(del_node); q->count--; // 仅当队列从满变为非满时,唤醒等待full的线程 if (q->count == q->size - 1) { pthread_cond_signal(&q->full); } pthread_mutex_unlock(&q->mutex); return true; }
额外注意事项
- 队列初始化:必须正确初始化互斥锁和条件变量:
bool queue_init(queue_t *q, int size) { if (q == NULL || size <= 0) { return false; } q->head = NULL; q->tail = NULL; q->size = size; q->count = 0; pthread_mutex_init(&q->mutex, NULL); pthread_cond_init(&q->full, NULL); pthread_cond_init(&q->empty, NULL); return true; }
- 销毁队列:使用完毕后要销毁互斥锁和条件变量,避免资源泄漏:
void queue_destroy(queue_t *q) { if (q == NULL) return; // 先清空所有节点 node_t *curr = q->head; while (curr != NULL) { node_t *next = curr->next; free(curr); curr = next; } pthread_mutex_destroy(&q->mutex); pthread_cond_destroy(&q->full); pthread_cond_destroy(&q->empty); }
内容的提问来源于stack exchange,提问作者MonstBlu
相关产品推荐
相关产品推荐

