并发编程(c++)——5.事件驱动
在并发编程中除了池和流的方式外还存在一种基本形式就是事件驱动。事件驱动的思想是使用一个线程不断循环处理任务将任务分发给其他复用的线程这样就通过单线程处理大量任务。发展历程io密集任务可以使用多线程一个io使用一个线程。但是如果任务过多比如达到百万级此时线程数量也会达到百万级别此时系统支持不了会崩溃。或者说使用线程池但是线程数量也需要很大频繁的切换线程也会带来大量的开销。这里有一个前提是io任务的处理机制基本一致可以用一个函数处理大量任务。此时可以考虑一种方式使用少量线程完成大量io任务。使用一个死循环一个队列队列中存储io任务死循环中不断处理io,这样就可以通过单线程处理百万io。但是这样会有阻塞问题处理io会使cpu等待所以需要将请求io和处理io分离。这样cpu只处理请求io处理io交给其他线程处理能充分利用cpu资源。同时还有一个问题循环内部会查询io任务队里,但如果io队列里没有任务这个循环就没有意义此时cpu会空转浪费资源。所以需要一种机制当io队列为空时让cpu等待当有任务时再唤醒cpu继续处理任务。背景问题1.使用多线程处理io密集任务当线程数量过大带来系统支持线程数不足线程切换资源消耗大。2.cpu和io处理时间差大带来的阻塞问题。3.非阻塞循环带来cpu空转。解决方案1.循环使用一个死循环不断读取任务和将任务分配给处理器。解决多线程处理使用单线程实现。2.分离发起io请求后不等待io返回继续处理其他任务当io返回后再处理io返回结果。解决阻塞问题。3.监督循环内部监视任务当任务为空时让cpu等待当有任务时再唤醒cpu继续处理任务。解决cpu空转问题。实现将所有任务抽象为不同的数据和对应的处理方式这就带获得了各个组成部分。实现因素1.事件将类型和数据抽象为一个结构体这个结构体就是事件。2.任务队列将要处理的事件放入队列中循环从队列中获取事件处理事件。3.处理器队列将任务类型和处理方式抽象为一个map,key为任务类型value为处理方式,放置在一个队列中处理任务时搜索这个队列找到对应任务类型执行处理方式。4.注册将处理器注册到处理器队列中。5.循环死循环调度任务队列和处理器队列监督任务队列当任务队列为空时让cpu等待当有任务时再唤醒cpu继续处理任务。6.分发有任务时查找任务对应的处理器将数据输入处理器中处理数据。#includestring#includequeue#includemap#includevector#includefunctional#includemutexstructevent{inttype;std::string data;};// 事件驱动类用于处理事件驱动的程序classEventDrive{private:// 事件队列用于存储待处理的事件std::queueeventqueue_events;// 事件处理器映射表键为事件类型值为对应的事件处理函数列表std::mapint,std::vectorstd::functionvoid(constevent)map_event_handlers;// 互斥锁用于保证线程安全std::mutex mut;// 运行状态标志true表示正在运行false表示已停止boolis_running;public:// 注册处理器为特定类型的事件注册一个处理函数voidon(inttype,std::functionvoid(constevent)handler);// 循环处理事件持续从队列中取出事件并处理直到is_running为falsevoidrun();// 添加事件将新事件添加到事件队列中voidadd_event(inttype,std::string data);// 处理事件根据事件类型查找并执行对应的处理函数voidhandle_event(constevente);// 停止事件驱动voidstop();};// 注册事件voidEventDrive::on(inttype,std::functionvoid(constevent)handler){map_event_handlers[type].push_back(handler);}// 循环处理事件voidEventDrive::run(){is_runningtrue;while(is_running){if(queue_events.empty()){continue;}else{std::lock_guardstd::mutexlock(mut);event equeue_events.front();queue_events.pop();handle_event(e);}std::this_thread::sleep_for(std::chrono::milliseconds(1));}}// 添加事件voidEventDrive::add_event(inttype,std::string data){std::lock_guardstd::mutexlock(mut);event e;e.typetype;e.datadata;queue_events.push(e);}// 处理事件voidEventDrive::handle_event(constevente){autoitmap_event_handlers.find(e.type);if(it!map_event_handlers.end()){for(autohandler:it-second){handler(e);}}}// 停止事件驱动voidEventDrive::stop(){is_runningfalse;}使用1.注册将处理器以函数的方式注册到处理器队列中。2.分析线程循环将事件驱动的循环在主线程外部执行这样主线程用于输入任务。3.载入任务将任务以事件的方式载入任务队列中。#includeevent_drive.hpp#includeiostreamintmain(){EventDrive envent_drive;//注册事件envent_drive.on(1,[](constevente){std::couthandler 1,收到事件1e.datastd::endl;});envent_drive.on(2,[](constevente){std::couthandler 2,收到事件2e.datastd::endl;});envent_drive.on(1,[](constevente){std::couthandler 3,也收到事件1e.datastd::endl;});// 启动事件循环std::threadloop_thread([envent_drive](){envent_drive.run();});// 发送事件envent_drive.add_event(1,data 1);envent_drive.add_event(2,data 2);envent_drive.add_event(1,data 3);// 停止事件循环std::this_thread::sleep_for(std::chrono::milliseconds(100));envent_drive.stop();loop_thread.join();return0;}结果handler 1,收到事件1data 1 handler 3,也收到事件1data 1 handler 2,收到事件2data 2 handler 1,收到事件1data 3 handler 3,也收到事件1data 3总结使用事件驱动的方式将任务抽象为事件将处理方式抽象为处理器将任务和处理器注册到事件驱动中事件驱动循环处理任务。

相关新闻

三步构建OFD转PDF自动化工作流:Ofd2Pdf技术解析与实战指南

三步构建OFD转PDF自动化工作流:Ofd2Pdf技术解析与实战指南

三步构建OFD转PDF自动化工作流:Ofd2Pdf技术解析与实战指南 【免费下载链接】Ofd2Pdf Convert OFD files to PDF files. 项目地址: https://gitcode.com/gh_mirrors/ofd/Ofd2Pdf Ofd2Pdf作为一款专注于OFD格式转PDF的开源工具,通过简洁的图形界面和…

2026/6/18 13:19:38阅读更多 →
SK-S12XDP512-A开发板硬件配置与调试实战指南

SK-S12XDP512-A开发板硬件配置与调试实战指南

1. 项目概述 如果你刚拿到一块像SK-S12XDP512-A这样的开发板,面对密密麻麻的跳线帽和一堆外设接口,是不是有点无从下手?我当年第一次接触这类飞思卡尔(现恩智浦)的HCS12X系列开发板时,也有同样的感觉。这块…

2026/6/18 13:19:38阅读更多 →
深入解析CAN控制器消息缓冲区:从寄存器编程到实战应用

深入解析CAN控制器消息缓冲区:从寄存器编程到实战应用

1. 项目概述与核心价值如果你正在开发汽车电子、工业控制或者机器人项目,并且用到了CAN总线,那么你大概率已经和CAN控制器的“消息缓冲区”打过交道了。这东西在数据手册里通常就几页,一堆寄存器地址和位定义,看得人头大。但说穿了…

2026/6/18 13:19:38阅读更多 →
机器学习模型可视化:四层诊断体系与工业级实操指南

机器学习模型可视化:四层诊断体系与工业级实操指南

1. 这不是画图,是给模型做“X光”和“体检报告”你有没有过这种经历:训练完一个线性回归模型,R高达0.92,心里美滋滋;可一拿到新数据,预测结果却像抛硬币——有时准得离谱,有时偏得离谱。或者&am…

2026/6/18 15:56:14阅读更多 →
NXP实时边缘软件实战:从Preempt-RT到TSN的工业物联网确定性架构

NXP实时边缘软件实战:从Preempt-RT到TSN的工业物联网确定性架构

1. 项目概述:工业物联网的确定性基石在工业自动化、机器人控制、汽车电子这些领域里,系统响应的“准时性”和“确定性”远比“快”更重要。想象一下,一个机械臂的控制指令晚了几个毫秒,或者一条生产线上的传感器数据因为网络拥堵而…

2026/6/18 15:56:14阅读更多 →
免费开源几何字体Outfit:9种字重打造品牌设计新革命

免费开源几何字体Outfit:9种字重打造品牌设计新革命

免费开源几何字体Outfit:9种字重打造品牌设计新革命 【免费下载链接】Outfit-Fonts The most on-brand typeface 项目地址: https://gitcode.com/gh_mirrors/ou/Outfit-Fonts 还在为品牌设计寻找完美字体吗?Outfit字体就是你的终极解决方案&#…

2026/6/18 15:56:14阅读更多 →
RTX 3090本地部署FLUX.2实战指南:显存优化与精度控制

RTX 3090本地部署FLUX.2实战指南:显存优化与精度控制

1. 项目概述:为什么一个RTX 3090能跑动FLUX.2,又为什么它值得你花三小时调通FLUX.2不是某个厂商发布的消费级软件,而是由Black Forest Labs开源的一套高保真图像生成模型架构——它不叫“Stable Diffusion的升级版”,而是一次底层…

2026/6/18 15:56:14阅读更多 →
Flux AI图像生成器实战指南:高精度可控文生图工作流

Flux AI图像生成器实战指南:高精度可控文生图工作流

1. 这不是又一个“AI画图工具测评”,而是一份 Flux 实战手记 Flux AI Image Generator——这个名字最近在设计圈、内容创作群和独立开发者私聊里出现的频率,高得有点反常。它不靠铺天盖地的广告,也不靠明星代言,而是靠一批批实际用…

2026/6/18 15:56:14阅读更多 →
LLaMA微调、PaLM-E对齐与Consistency Model实战指南

LLaMA微调、PaLM-E对齐与Consistency Model实战指南

1. 这不是一份“新闻简报”,而是一份AI从业者三月实战手记2023年3月的AI圈,没有冷场,只有加速。如果你在当月打开过Hugging Face模型库、刷过arXiv首页、或者调试过一次API调用延迟,你大概率会感受到一种明确的节奏变化&#xff1…

2026/6/18 15:51:09阅读更多 →
ZigBee HA智能家居开发实战:从集群模型到NXP JN516x代码实现

ZigBee HA智能家居开发实战:从集群模型到NXP JN516x代码实现

1. ZigBee HA:智能家居的“通用语言”与开发基石如果你正在或计划踏入智能家居设备开发领域,尤其是基于ZigBee协议,那么“ZigBee Home Automation”这个名词你一定不陌生。它不仅仅是ZigBee联盟定义的一套应用层规范,更是确保不同…

2026/6/18 0:00:24阅读更多 →
Java毕设选题推荐:基于 Spring Boot 的个人随笔博客运维管理系统的设计与实现 基于 Spring Boot 的用户原创博客分享社区【附源码、mysql、文档、调试+代码讲解+全bao等】

Java毕设选题推荐:基于 Spring Boot 的个人随笔博客运维管理系统的设计与实现 基于 Spring Boot 的用户原创博客分享社区【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/6/18 0:00:24阅读更多 →
JN517x嵌入式开发实战:看门狗、脉冲计数器与I2C接口的深度解析与避坑指南

JN517x嵌入式开发实战:看门狗、脉冲计数器与I2C接口的深度解析与避坑指南

1. 项目概述在嵌入式开发领域,尤其是基于NXP JN517x这类无线微控制器的项目中,系统稳定性和与外设的可靠交互是两大核心挑战。前者关乎产品能否在无人值守的复杂环境中长期运行,后者则决定了设备能否准确感知世界并与其他芯片“对话”。JN517…

2026/6/18 0:00:24阅读更多 →