【Linux】生产者消费者模型 引言生产者消费者模型是一种多进程多线程同步互斥问题有三种关系两种角色一个交易场所生产者和生产者之间的互斥关系消费者和消费者之间的互斥关系生产者和消费者之间的互斥和同步关系一个共享资源是特定结构的内存空间可以是阻塞队列或环形队列本质是多个线程高效通信做到解耦合使用queue模拟判断阻塞队列与普通队列的区别在于当队列为空时从队列获取元素操作会被阻塞知道队列放入元素当队列为满时向队列放入元素也会阻塞直到有元素被从队列取出注意STL容器本身不是线程安全的由于设计时保证高效性例如push和pop需要维护同步关系生产和消费关系使用条件变量实现多线程的同步生产者消费者使用同一把锁不同的条件变量只要生产数据就通知消费const int defaultnum 5; using namespace std; templateclass T class BlockQueue { public: BlockQueue(int dn defaultnum/*, int index 0*/):capacity_(dn)/*, index_(index)*/ { pthread_mutex_init(p_mutex_, nullptr); // pthread_mutex_init(c_mutex_, nullptr); low_water_ capacity_ / 4; high_water_ (capacity_ *2)/3; //这里 2/3 等于0所以 high_water_ 也是0 if(low_water_ 0) low_water_ 1; if(high_water_ low_water_) high_water_ capacity_ -1; } void Push(const T data) //生产者生产保证互斥 { pthread_mutex_lock(p_mutex_); while(q_.size() high_water_) //这里插入的时候 0 0 会满足条件wait等待 { pthread_cond_wait(p_cond_, p_mutex_); } q_.push(data); pthread_cond_signal(c_cond_); //唤醒comsumer要在循环外面生产一个数据再消费 pthread_mutex_unlock(p_mutex_); } T Pop() { pthread_mutex_lock(p_mutex_); while(q_.size() 0) { pthread_cond_wait(c_cond_, p_mutex_); } T data q_.front(); q_.pop(); pthread_cond_signal(p_cond_); pthread_mutex_unlock(p_mutex_); return data; } string Getname() { name_ thread ; name_ to_string(index_); return name_; } ~BlockQueue() { pthread_mutex_destroy(p_mutex_); // pthread_mutex_destroy(c_mutex_); pthread_cond_destroy(p_cond_); pthread_cond_destroy(c_cond_); } private: int capacity_; int index_; string name_; std::queueT q_; pthread_mutex_t p_mutex_; // pthread_mutex_t c_mutex_; pthread_cond_t p_cond_; pthread_cond_t c_cond_; int low_water_; int high_water_; };void *Producer(void *args) { pthread_detach(pthread_self()); BlockQueueint *bq static_castBlockQueueint *(args); // 生产数据 while (true) { int data1 rand() % 10 1; bq-Push(data1); cout produced a number : data1 endl; sleep(1); } return nullptr; } void *Consumer(void *args) { pthread_detach(pthread_self()); BlockQueueint *bq static_castBlockQueueint *(args); // 生产数据 while (true) { int ret bq-Pop(); cout Consumed a number : ret endl; sleep(1); } return nullptr; } int main() { srand(time(nullptr) ^ getpid()); // BlockQueueint *bq new BlockQueueint(); // pthread_t c, p; // pthread_create(c, nullptr, Consumer, bq); // pthread_create(p, nullptr, Producer, bq); vectorpthread_t ctids(c_num); vectorpthread_t ptids(p_num); BlockQueueint *bp new BlockQueueint(); for (int i 0; i c_num; i) { // auto* args new auto(bind(bp, 10, i)); pthread_create(ctids[i], nullptr, Consumer, bp); } for (int i 0; i p_num; i) { // auto* args new auto(bind(bp, 10, i)); pthread_create(ptids[i], nullptr, Producer, bp); } cout create success endl; // for (auto i : ctids) // { // pthread_join(i, nullptr); // } // for (auto i : ptids) // { // pthread_join(i, nullptr); // } sleep(5); }情景2指派任务Task.hppconst char *oper -*/%; enum exitcode { DivZero 1, ModZero, UnKnow }; class Task { public: Task(int a, int b, char op) : a_(a), b_(b), op_(op), code_(0) {} void Run() { switch (op_) { case : resault_ a_ b_; break; case -: resault_ a_ - b_; break; case *: resault_ a_ * b_; break; case /: if (b_ 0) { code_ DivZero; } else { resault_ a_ / b_; } break; case %: if (b_ 0) { code_ ModZero; } else { resault_ a_ % b_; } break; default: code_ UnKnow; break; } } void operator()() { Run(); } string GetTask() { string s to_string(a_); s op_; s to_string(b_); s ? ; return s; } string GetRes() { string s to_string(a_); s op_; s to_string(b_); s ; if (code_ ! 0) { switch(code_) { case DivZero: s 除0错误; break; case ModZero: s 模0错误; break; case UnKnow: s 符号错误; break; } } else { s to_string(resault_); s [; s to_string(code_); s ]; } return s; } private: int a_, b_; char op_; int resault_; int code_ 0; };main.ccusing namespace std; const int c_num 3; const int p_num 1; void *Producer(void *args) { pthread_detach(pthread_self()); int opsize 5; BlockQueueTask *bq static_castBlockQueueTask *(args); // 生产数据 while (true) { int data1 rand() % 10 1; usleep(10); int data2 rand() % 3; char op oper[rand() % opsize]; Task t(data1, data2, op); bq-Push(t); cout Produce a task : t.GetTask() endl; sleep(1); } sleep(1); return nullptr; } void *Consumer(void *args) { pthread_detach(pthread_self()); BlockQueueTask *bq static_castBlockQueueTask *(args); // 处理任务 while (true) { Task ret bq-Pop(); ret(); cout Consumer get a resualt : ret.GetRes() endl; sleep(1); } sleep(1); return nullptr; } int main() { srand(time(nullptr) ^ getpid()); // BlockQueueint *bq new BlockQueueint(); // pthread_t c, p; // pthread_create(c, nullptr, Consumer, bq); // pthread_create(p, nullptr, Producer, bq); vectorpthread_t ctids(c_num); vectorpthread_t ptids(p_num); BlockQueueTask *bp new BlockQueueTask(); for (int i 0; i c_num; i) { // auto* args new auto(bind(bp, 10, i)); pthread_create(ctids[i], nullptr, Consumer, bp); } for (int i 0; i p_num; i) { // auto* args new auto(bind(bp, 10, i)); pthread_create(ptids[i], nullptr, Producer, bp); } cout create success endl; // for (auto i : ctids) // { // pthread_join(i, nullptr); // } // for (auto i : ptids) // { // pthread_join(i, nullptr); // } sleep(50); }知识点判断条件变量使用为什么在加锁和解锁之间判断也是访问临界资源伪唤醒会向队列push错误的数据所以要用while循环调用pthread_cond_wait会自动释放锁线程进入等待队列

相关新闻

最新新闻

嵌入式屏幕显示中文怎么选?u8g2_wqy 中文字体库完整指南

嵌入式屏幕显示中文怎么选?u8g2_wqy 中文字体库完整指南

嵌入式屏幕显示中文怎么选?u8g2_wqy 中文字体库完整指南 【免费下载链接】u8g2_wqy 适合 u8g2 的中文字体,采用文泉驿点阵宋体作为源本,提供 12x12、13x13、14x14、15x15 和 16x16 点阵字库。 项目地址: https://gitcode.com/gh_mirrors/u8…

2026/8/20 17:56:41
一套完整的开源社交媒体数据采集工具指南:小红书、抖音、B站等五大平台数据一次搞定

一套完整的开源社交媒体数据采集工具指南:小红书、抖音、B站等五大平台数据一次搞定

一套完整的开源社交媒体数据采集工具指南:小红书、抖音、B站等五大平台数据一次搞定 【免费下载链接】MediaCrawler-new 项目地址: https://gitcode.com/GitHub_Trending/me/MediaCrawler-new MediaCrawler-new 是一套主打"省心"的开源社交媒体数…

2026/8/20 17:56:41
QQ空间历史说说备份神器GetQzonehistory:10分钟把回忆完整搬回本地

QQ空间历史说说备份神器GetQzonehistory:10分钟把回忆完整搬回本地

QQ空间历史说说备份神器GetQzonehistory:10分钟把回忆完整搬回本地 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory QQ空间历史说说备份,是很多老用户一直想做又不…

2026/8/20 17:56:41
PS4金手指管理器免费完整指南:GoldHEN Cheats Manager让1490+款游戏作弊码一键生效

PS4金手指管理器免费完整指南:GoldHEN Cheats Manager让1490+款游戏作弊码一键生效

PS4金手指管理器免费完整指南:GoldHEN Cheats Manager让1490款游戏作弊码一键生效 【免费下载链接】GoldHEN_Cheat_Manager GoldHEN Cheats Manager 项目地址: https://gitcode.com/gh_mirrors/go/GoldHEN_Cheat_Manager 深夜两点,你又一次在同一…

2026/8/20 17:56:41
Umi-OCR免费离线OCR实战教程:截图识别、批量图片、扫描PDF文字提取一键搞定

Umi-OCR免费离线OCR实战教程:截图识别、批量图片、扫描PDF文字提取一键搞定

Umi-OCR免费离线OCR实战教程:截图识别、批量图片、扫描PDF文字提取一键搞定 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成…

2026/8/20 17:56:41
表格、公式和参考文献算进重复率吗?这几处乱改一轮就白降了!

表格、公式和参考文献算进重复率吗?这几处乱改一轮就白降了!

表格、公式和参考文献算进重复率吗?这几处乱改一轮就白降了! 先说一个总原则 算不算,取决于系统有没有把它识别出来,不取决于你觉得它该不该算。 很多人的误解是:参考文献本来就不该算进重复率,所以我不…

2026/8/20 17:51:41