在多线程编程中,生产者-消费者模式是一种常见的设计模式,用于解决线程间的数据同步问题。最近,我在 Linux 和 macOS 上运行同一个生产者-消费者模式的程序时,发现它们表现出不同的行为。本文将介绍这个现象、分析其原因,并提供一些改进建议。

现象描述

在 Linux 上运行程序时,消费者线程能够及时处理生产者线程生成的任务,每个任务几乎在生产后立即被处理。然而,在 macOS 上运行同一程序时,生产者线程连续生成多个任务,而消费者线程似乎没有及时处理它们。

代码实现

以下是我用于测试的代码:

#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <list>
#include <semaphore.h>
#include <iostream>class Task {
public:Task(int taskid) {this->taskid = taskid;}void doTask() {std::cout << "taskID: " << taskid << ", threadID: " << pthread_self() << std::endl;}private:int taskid;
};pthread_mutex_t mymutex;
std::list<Task*> tasks;
sem_t mysemaphore;void* consumer_thread(void* arg) {Task* pTask = NULL;while (true) {if (sem_wait(&mysemaphore) != 0)continue;if (tasks.empty())continue;pthread_mutex_lock(&mymutex);pTask = tasks.front();tasks.pop_front();pthread_mutex_unlock(&mymutex);pTask->doTask();delete pTask;}return NULL;
}void* producer_thread(void* arg) {int taskid = 0;Task* pTask = NULL;while (true) {pTask = new Task(taskid);pthread_mutex_lock(&mymutex);tasks.push_back(pTask);std::cout << "produce a task, taskid: " << taskid << ", threadid: " << pthread_self() << std::endl;pthread_mutex_unlock(&mymutex);sem_post(&mysemaphore);taskid++;sleep(1);}return NULL;
}int main() {pthread_mutex_init(&mymutex, NULL);sem_init(&mysemaphore, 0, 0);pthread_t consumerThreadID[5];for (int i = 0; i < 5; ++i) {pthread_create(&consumerThreadID[i], NULL, consumer_thread, NULL);}pthread_t producerThreadID;pthread_create(&producerThreadID, NULL, producer_thread, NULL);pthread_join(producerThreadID, NULL);for (int i = 0; i < 5; ++i) {pthread_join(consumerThreadID[i], NULL);}sem_destroy(&mysemaphore);pthread_mutex_destroy(&mymutex);return 0;
}

Mac运行结果

在这里插入图片描述

Linux运行结果

在这里插入图片描述

原因分析

  1. 信号量和互斥锁的实现差异

    • macOS 和 Linux 对信号量和互斥锁底层的实现不同,这可能影响线程的调度和同步行为。
  2. 线程调度策略

    • Linux 和 macOS 使用不同的调度算法。Linux 通常使用完全公平队列调度器(CFS),而 macOS 使用基于优先级的调度策略。这可能导致线程切换的时机不同。
  3. 输出函数的行为

    • std::cout 在不同系统上的缓冲行为可能不同。在 macOS 上,std::cout 的缓冲可能导致输出延迟。
  4. 系统调度器的影响

    • macOS 的调度器可能更倾向于将同一线程的生产者线程优先调度,导致多个任务快速连续地被生产。

改进建议

  1. 调整线程优先级

    • 在 macOS 上,可以尝试设置消费者线程的优先级高于生产者线程。
  2. 增加调试输出

    • sem_postpthread_mutex_unlock 之后添加调试输出,检查信号量和互斥锁是否被正确释放。
  3. 减少生产者线程的生产速度

    • 在生产者线程中增加更长的 sleep 时间,使消费者线程有更多机会处理任务。
  4. 检查编译器和运行时环境

    • 确保在两个系统上使用相同版本的编译器和运行时库。
  5. 使用条件变量替代信号量

    • 条件变量可能在不同系统上表现更一致。
  6. 使用 std::asyncstd::future 替代 POSIX 线程

    • 如果可以使用 C++11 或更高版本,可以考虑使用 std::asyncstd::future 替代 POSIX 线程。

示例改进代码

以下是一个使用条件变量的改进示例:

#include <pthread.h>
#include <condition_variable>
#include <list>
#include <iostream>class Task {
public:Task(int taskid) {this->taskid = taskid;}void doTask() {std::cout << "taskID: " << taskid << ", threadID: " << pthread_self() << std::endl;}private:int taskid;
};std::condition_variable cv;
std::mutex cv_m;
std::list<Task*> tasks;
bool task_ready = false;void* consumer_thread(void* arg) {Task* pTask = NULL;while (true) {std::unique_lock<std::mutex> lock(cv_m);cv.wait(lock, []{ return task_ready; });if (!tasks.empty()) {pTask = tasks.front();tasks.pop_front();task_ready = false;}lock.unlock();if (pTask) {pTask->doTask();delete pTask;}}return NULL;
}void* producer_thread(void* arg) {int taskid = 0;Task* pTask = NULL;while (true) {pTask = new Task(taskid);{std::unique_lock<std::mutex> lock(cv_m);tasks.push_back(pTask);task_ready = true;}cv.notify_one();taskid++;sleep(1);}return NULL;
}int main() {pthread_t consumerThreadID[5];for (int i = 0; i < 5; ++i) {pthread_create(&consumerThreadID[i], NULL, consumer_thread, NULL);}pthread_t producerThreadID;pthread_create(&producerThreadID, NULL, producer_thread, NULL);pthread_join(producerThreadID, NULL);for (int i = 0; i < 5; ++i) {pthread_join(consumerThreadID[i], NULL);}return 0;
}

结论

通过调整线程优先级、增加调试输出、控制生产速度、使用条件变量等方式,可以更好地确保生产者和消费者线程之间的平衡,使任务能够及时被处理。希望这些建议能帮助你在不同操作系统上实现更稳定和高效的生产者-消费者模式。

参考资源

  • C++ 条件变量
  • C++服务端开发精髓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85708.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85708.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/85708.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JS-4.1-DOM获取元素操作】深入理解DOM操作:高效获取页面元素的方法与实践

在现代Web开发中&#xff0c;DOM&#xff08;文档对象模型&#xff09;操作是前端工程师的必备技能。而DOM操作的第一步&#xff0c;往往是从页面中获取我们需要操作的元素。本文将全面介绍各种获取页面元素的方法&#xff0c;分析它们的性能特点&#xff0c;并提供最佳实践建议…

UE5错误 Linux离线状态下错误 请求失败libcurl错误:6无法解析主机名

UE5错误 Linux离线状态下错误 请求失败libcurl错误&#xff1a;6无法解析主机名 完整描述问题解析解决方法 完整描述 loghttp&#xff1a;warning&#xff1a;ox015cba21400:request failed libcurl error :6 (couldn’t resolve host name ) 问题解析 这是因为在离线状态下…

深度学习实战111-基于神经网络的A股、美股、黄金对冲投资策略(PyTorch LSTM)

文章目录 一、A股与美股对冲互补投资方案1. 现象与逻辑2. 对冲互补投资思路3. 资金分配样例4. 最大化收益的关键二、对冲互补投资思路1. 资金分配原则2. 动态调整机制3. 对冲操作三、投资方案样例1. 初始资金分配(假设总资金10万元)2. 动态调整举例情景一:美股进入牛市,A股…

在线教育平台敏捷开发项目

项目背景 产品名称&#xff1a;LearnFlow&#xff08;在线学习平台&#xff09; 核心目标&#xff1a;6个月内上线MVP&#xff08;最小可行产品&#xff09;&#xff0c;支持课程学习、进度跟踪、测验功能。 团队构成&#xff1a; 产品负责人&#xff08;PO&#xff09;1人 S…

C++面试题(35)-------找出第 n 个丑数(Ugly Number)

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 我们把只包含质因子 2、3 和 5 的数称作丑数&#xff08;Ugly Number&#xff09;。例如 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 请编写一个函数&#xff0c;找出第 n …

Day03_数据结构(手写)

01.数据结构画图 02. //11.按值查找返回位置 int search_value(node_p H,int value) { if(HNULL){ printf("入参为空.\n"); return -1; …

【Java学习笔记】Collections工具类

Collections 工具类 基本介绍 &#xff08;1&#xff09;Collections 中提供了一系列静态方法对集合元素进行排序&#xff0c;查询和修改等操作 &#xff08;2&#xff09;操作对象&#xff1a;集合 常用方法一览表 方法描述reverse(List<?> list)反转 List 中元素…

spring-webmvc @ResponseBody 典型用法

典型用法 基本用法&#xff1a;返回 JSON 数据 GetMapping("/users/{id}") ResponseBody public User getUser(PathVariable Long id) {return userService.findById(id); }Spring 自动使用 Jackson&#xff08;或其他 HttpMessageConverter&#xff09;将 User 对…

AI-调查研究-08-跑步分析研究 潜在伤害与预防 不同年龄段与性别的情况

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月16日更新到&#xff1a; AI炼丹日志-29 - 字节…

AI任务相关解决方案9-深度学习在工业质检中的应用:基于DeepLabv3+模型的NEU-seg数据集语义分割研究

大家好我是微学AI,今天给大家介绍一下AI任务相关解决方案9-深度学习在工业质检中的应用:基于DeepLabv3+模型的NEU-seg数据集语义分割研究。DeepLabv3+模型在NEU-seg数据集上实现了高达87.65%的平均交并比(mIoU),为金属表面缺陷的高精度检测提供了有力工具。本文将详细探讨Dee…

mysql JSON_EXTRACT JSON_UNQUOTE 函数

在处理mysql 有存储的json字段&#xff0c;需要提取时候发现JSON_EXTRACT函数&#xff0c;发现此函数提取后会带有引号&#xff0c;组合使用JSON_UNQUOTE 可去掉引号&#xff01; JSON_EXTRACT 函数概述 JSON_EXTRACT是MySQL中用于从JSON文档中提取数据的函数&#xff0c;语法…

Prompt:更好的提示与迭代

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 1 引言1.1 引用资料 2 更好的提示2.1 情景学习IC…

SQL85 统计每个产品的销售情况

SQL85 统计每个产品的销售情况 好复杂&#xff0c;俺不中了。。 问题描述 本查询旨在分析2023年各产品的销售情况&#xff0c;包括&#xff1a; 每个产品的总销售额、单价、总销量和月均销售额每个产品销量最高的月份及其销量每个产品购买量最高的客户年龄段 解题思路 1. 基…

Django MAC Pycharm 命令行建立项目,注册app运行失败,找不到views导入包

相对复杂的情况 你没有直接在Pycharm中建立一个Django项目&#xff0c;而是直接建立某个项目或者打开某个项目&#xff0c;使用命令后安装Django后&#xff0c;使用命令后建立了Django项目&#xff0c;尽管你的目录尽可能干净&#xff0c;只有Django项目&#xff0c;但是这仍然…

窄带和宽带谁略谁优

窄带&#xff08;Narrowband&#xff09;与宽带&#xff08;Broadband&#xff09;深度对比 ——涵盖 优缺点、适用场景、调制方式 1. 窄带&#xff08;Narrowband&#xff09; 1.1 核心特点 带宽&#xff1a;≤25 kHz&#xff08;典型值&#xff0c;如NB-IoT仅占用180kHz&a…

李佳琦直播间618收官:6成销量为国货,多品类增超25%

618大促迎来收官&#xff0c;作为电商消费的关键风向标&#xff0c;李佳琦直播间生动呈现了当下消费市场的多元趋势。 据「TMT星球」了解&#xff0c;在长达近40天的大促里&#xff0c;李佳琦直播间不仅延续过往的高人气与强带货力&#xff0c;更在高质价比产品、高质量服务保…

c++ noexcept关键字

noexcept 是 C11 中引入的一个关键字&#xff0c;用来标记函数声明&#xff0c;表示该函数不会抛出异常。它可以用于函数、函数指针、Lambda 表达式等。使用 noexcept 可以帮助编译器进行优化&#xff0c;提高代码的执行效率&#xff0c;并且让程序在处理异常时更加明确。 1. …

腾讯混元3D制作简单模型教程-2

以下是腾讯混元3D制作简单模型的详细教程&#xff0c;整合最新版本特性&#xff08;截至2025年6月&#xff09;&#xff0c;操作门槛低且无需专业基础&#xff1a; &#x1f5a5; 一、在线生成&#xff08;最快30秒完成&#xff09; ‌访问平台‌ 打开 腾讯混元3D创作引擎官网…

阿里云申请ssl证书,同时需要绑定域名,下载nginx压缩包,nginx添加证书路径即可

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、ssl是什么&#xff1f;二、登录阿里云三、图片教程四、添加域名前缀&#xff08;www&#xff09;如&#xff1a;www.baidu.com总结 一、ssl是什么&#xff1f; …

额度互动促进金融健康,蚂蚁消金创新智能实时交互式风控系统

“蚂蚁消金希望利用交互式智能风控技术&#xff0c;挖掘年轻人努力成长的证明”。6月19日&#xff0c;在上海举行的2025中国国际金融展上&#xff0c;蚂蚁消金首席风险官林嘉南分享了&#xff0c;如何将大模型技术应用在交互式智能风控领域&#xff0c;从而促进额度的互动性&am…