news 2026/10/28 10:17:42

Linux 学习笔记(三十四):线程同步——条件变量与生产消费者模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 学习笔记(三十四):线程同步——条件变量与生产消费者模型

一、 为什么有了互斥锁还需要条件变量?

互斥锁解决了数据冲突,但无法解决“执行顺序”的问题。如果消费者一直抢锁去查仓库(死循环),会导致 CPU 空转(忙等待)。条件变量可以让线程在条件不满足时进入睡眠(阻塞),把 CPU 让出来,直到条件满足时被其他线程唤醒。

二、 核心 API 与易错点

  • pthread_cond_wait(cond, mutex):等待条件满足。

  • pthread_cond_signal(cond):唤醒一个等待的线程。

面试极度高频:为什么 wait 必须传互斥锁?
因为在进入睡眠前,必须释放锁;在醒来后,必须重新获取锁。把“释放锁”和“进入睡眠”合并成一个原子操作,可以防止在释放锁后、入睡前,错过了生产者发出的唤醒信号。

为什么判断条件必须用 while 循环?
因为存在“伪唤醒”(操作系统层面的原因)或多个线程被同时唤醒,醒来后必须再次检查队列状态,否则会导致越界访问。

三、 生产者消费者模型(321原则)

  • 3 种关系:生产者与生产者(互斥)、消费者与消费者(互斥)、生产者与消费者(同步+互斥)。

  • 2 个角色:生产者、消费者。

  • 1 个交易场所:阻塞队列(BlockingQueue)。

四、 实战:基于阻塞队列的并发控制


通过手写BlockQueue模板类,将生产者与消费者解耦。当队列满时,生产者阻塞;当队列空时,消费者阻塞。极大地提高了程序的健壮性和 CPU 利用率。

(选做:概述一下线程池的架构:提前创建好固定数量的线程,结合任务队列,一旦有任务丢进队列,线程就唤醒去抢任务执行,避免频繁创建销毁线程的开销)

自我实战操作

cd ~/linux_study mkdir sync_test cd sync_test
实战 1:手写一个阻塞队列
vim BlockQueue.hpp

(输入以下代码,结合了你之前学的锁和刚学的条件变量)

#pragma once #include <iostream> #include <queue> #include <pthread.h> template <typename T> class BlockQueue { public: BlockQueue(int cap = 10) : _cap(cap) { pthread_mutex_init(&_mutex, nullptr); pthread_cond_init(&_cond_pro, nullptr); // 给生产者准备的条件变量 pthread_cond_init(&_cond_con, nullptr); // 给消费者准备的条件变量 } ~BlockQueue() { pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond_pro); pthread_cond_destroy(&_cond_con); } // 生产者接口 void Push(const T& in) { pthread_mutex_lock(&_mutex); // 如果队列满了,生产者就去睡觉 while (_q.size() >= _cap) { pthread_cond_wait(&_cond_pro, &_mutex); } _q.push(in); // 生产了东西,唤醒消费者 pthread_cond_signal(&_cond_con); pthread_mutex_unlock(&_mutex); } // 消费者接口 void Pop(T* out) { pthread_mutex_lock(&_mutex); // 如果队列空了,消费者就去睡觉 while (_q.empty()) { pthread_cond_wait(&_cond_con, &_mutex); } *out = _q.front(); _q.pop(); // 消费了东西,唤醒生产者 pthread_cond_signal(&_cond_pro); pthread_mutex_unlock(&_mutex); } private: std::queue<T> _q; int _cap; pthread_mutex_t _mutex; pthread_cond_t _cond_pro; pthread_cond_t _cond_con; };
实战 2:用两个线程测试阻塞队列
vim main.cc

(输入以下代码)

#include <iostream> #include <unistd.h> #include "BlockQueue.hpp" void* Consumer(void* arg) { BlockQueue<int>* bq = (BlockQueue<int>*)arg; while (true) { int data; bq->Pop(&data); std::cout << "消费者消费了数据: " << data << std::endl; sleep(1); // 模拟消费处理耗时,消费慢,生产快 } return nullptr; } void* Producer(void* arg) { BlockQueue<int>* bq = (BlockQueue<int>*)arg; int data = 1; while (true) { bq->Push(data); std::cout << "生产者生产了数据: " << data << std::endl; data++; usleep(200000); // 生产快 } return nullptr; } int main() { BlockQueue<int>* bq = new BlockQueue<int>(5); // 仓库容量只有5 pthread_t c, p; pthread_create(&c, nullptr, Consumer, (void*)bq); pthread_create(&p, nullptr, Producer, (void*)bq); pthread_join(c, nullptr); pthread_join(p, nullptr); return 0; }

编译运行:

g++ main.cc -o main -lpthread ./main

👉现象:因为消费者睡1秒,生产者0.2秒放一个,很快队列就满了(5个)。此时生产者的while循环生效,进入 wait 睡眠,不再疯狂刷屏。等消费者取走一个,生产者才醒过来放一个。这就是完美的同步控制!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 10:17:29

插件式框架学习(1)

lianpeiliang/LearnFramework: 基于 C / Qt 5 的轻量级桌面插件框架学习项目&#xff0c;包含应用启动、命令与消息分发、插件加载及服务注册。 它是一个基于 C / Qt 5 的桌面插件框架学习版&#xff0c;目前运行后主要显示一个空窗口&#xff0c;还没有具体业务功能。 核心价…

作者头像 李华
网站建设 2026/10/28 10:13:58

LPC_经纬海拔转XYZ

LPC&#xff1a;Localization Planning and Control 输入&#xff1a;GNSS 输出 LLH(lat, lon, h)&#xff0c;WGS84&#xff08;纬度 φ&#xff0c;经度 λ&#xff0c;大地高 h&#xff09; 输出&#xff1a;ENU&#xff08;东、北、天&#xff09; / NED&#xff08;北、东…

作者头像 李华
网站建设 2026/10/28 10:13:03

PWA站点采集实战:Service Worker缓存机制拆解与动态内容完整提取方案

最近团队接了几个工业SaaS平台的数据采集需求,清一色都是PWA架构。一开始用常规的HTTP请求框架去做,要么拿到的是几天前的旧数据,要么页面骨架出来了但核心数据区域全是空的,抓下来的HTML全是缓存壳子。一开始以为是对方做了强反爬,调了代理、浏览器指纹都没用,最后抓包逐…

作者头像 李华
网站建设 2026/10/28 10:12:48

必知!Python 基于sklearn库的6个项目,解锁机器学习核心技能

基于 的 &#xff08;-Learn&#xff09;库的机器学习编程练习项目-Learn这个简称指的是中那个强大而且在很大程度上被使用的机器学习库, 它提供了丰富的算法和工具, 适用于各种各样的机器学习任务。以下是一些基于该库的机器学习编程练习项目。这些项目按照从基础到进阶的顺序…

作者头像 李华
网站建设 2026/10/28 10:12:47

Python入门难不难?新手最该学什么

“想学, 但是我们不知道从哪里开始”、“看视频的时候觉得特别简单, 可一动手去做的时候就卡住了”——这种情况几乎是每一个新手都会碰到的问题。其实, 这件事并没有像人们想象的那样难, 真正让人感到困难的地方不是语言本身, 而是你到底有没有使用恰当的学习顺序。一、先说结…

作者头像 李华
网站建设 2026/10/28 10:12:05

商品结构有没有被改:用Pillow定位局部像素差异

AI做商品图可能改变产品在画面中的轮廓、连接关系或可见细节&#xff0c;但一张差异图不能直接判断商品有没有变形。背景调整、压缩和光照变化也会造成像素差异。本文给出一个较窄的本地检查方法&#xff1a;在已经对齐的两张图片中&#xff0c;比较同一矩形区域&#xff0c;把…

作者头像 李华