惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Simon Willison's Weblog
Simon Willison's Weblog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
About on SuperTechFans
Last Week in AI
Last Week in AI
月光博客
月光博客
有赞技术团队
有赞技术团队
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
U
Unit 42
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
H
Hacker News: Front Page
Recent Announcements
Recent Announcements
C
CXSECURITY Database RSS Feed - CXSecurity.com
Latest news
Latest news
小众软件
小众软件
P
Palo Alto Networks Blog
PCI Perspectives
PCI Perspectives
Security Latest
Security Latest
S
Secure Thoughts
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
O
OpenAI News
S
Securelist
云风的 BLOG
云风的 BLOG
H
Help Net Security
T
Troy Hunt's Blog

博客园 - 蓝天上的云℡

事件编程之eventfd syslog日志查看器GUI图形界面,支持Windows/Linux/Macos开箱即用 ERRNO链条分析 ARM AMBA总线之AXI系 Linux Kernel Init Bootstrap 内核初始化启动 RK芯片平台GPIO控制 Linux USB子系统之Gadget设备端驱动 远程调试桥接-网络-ADB-GDB 斐讯N1盒子安装飞牛FNOS NAS 安卓以太网链路检测 安卓原生开发-Recovery使用minui绘制图形 蓝牙音频协议——安卓开发 RKxx系列的RK628摄像头配置影响HDMI出图 usb储存之BOT/UAS内核驱动 现代操作系统-音频处理技术1 Linux驱动底层 Linux驱动适配I2C/SPI例子 模块编译的pr_debug Linux内核/GKI内核主线更新-usb网卡名称变更引出的BUG 为Kernel代码生成VSCODE索引,快速跳转 安卓开机时间/性能优化 Linux/Golang/glibC系统调用 SGDMA与普通DMA Linux内核源码-存储驱动之 QSPI Flash golang数据转换技巧
事件驱动编程模式之EventLoop
蓝天上的云℡ · 2026-05-06 · via 博客园 - 蓝天上的云℡

事件驱动

优点:

  • 松耦合,开发者可以像调用函数一样 解耦式使用它。
  • 独立隔离,不同事件不互相影响
  • 快速开发,不需要每次都为一段执行代码重新设计异步实现
  • 降低复杂度
  • 低消耗,节省cpu资源
  • 异步使用场景广,适合复杂、高动态的工作流
    缺点:
  • 难以测试,这也是事件的缺点:并发时序性每次都不完全一样,溯源调试复杂,代码上已经看不出顺序。尽管有trace方式,但无法完全一致地重放追溯。
  • 集中式的分发,发起端单点故障容易发生中心雪崩式资源耗尽,一般高可行情况下需要配置限流和熔断。

EDA

云架构中常常是更大架构层面的EDA, Event-driven architecture事件驱动架构,是一种跨服务跨系统的分布式现代架构模式,基于发布-订阅的消息异步通讯架构。
Notes: EDA上架构层面的概念,与设计模式的EventLoop并不在同一层概念,但本质上都是事件驱动思想的衍生。

https://bytebytego.com/guides/how-do-message-queue-architectures-evolve/

image

image

局部图:
image

C的常见最小实现

Event -> EventLoop with Queue -> HandlerA,HandlerB,HanlderC...

EventLoop

对于小型程序来说,实现EDA的一种方式就是以EventLoop事件循环为中心,通过发布订阅的方式来实现微型EDA。
最小的EDA需要 EventPublisher-> Event ->EventLoop->EventHandlers

组成部分:

Event Loop 实现原理

数据结构

classDiagram class EventQueue { Event buffer[256] int head int tail int size pthread_mutex_t mutex pthread_cond_t not_empty pthread_cond_t not_full } class Event { EventType type int param1 int param2 void* data } class HandlerTable { EventHandler handlers[EVENT_TYPE_COUNT] +register_handler(type, fn) +handle_event(e) } EventQueue o-- Event : "buffer 存储" HandlerTable ..> Event : "按 type 分发" style EventQueue fill:#2d6a4f,color:#fff,stroke:#1b4332 style Event fill:#264653,color:#fff,stroke:#1d3557 style HandlerTable fill:#e76f51,color:#fff,stroke:#c1440e

push 与 pop 的同步交互

sequenceDiagram box rgb(42,84,122) 生产者 participant P as 生产者线程 end box rgb(231,111,81) 同步原语 participant M as mutex participant Q as queue participant NE as cond not_empty participant NF as cond not_full end box rgb(45,106,79) 消费者 participant C as event_loop_thread end Note over C: 🟢 while(running) 循环开始 C->>M: 🔒 pthread_mutex_lock() Note over C: size==0, 队列空 C->>NE: 😴 pthread_cond_wait(not_empty, mutex) Note over C: ⚠️ 原子地释放 mutex 并挂起 P->>M: 🔒 pthread_mutex_lock() Note over P: 获得锁 P->>Q: 📝 buffer[tail] = event<br/>tail = (tail+1) % MAX<br/>size++ P->>NE: 📢 pthread_cond_broadcast(not_empty) Note over NE: 唤醒所有等待者 P->>M: 🔓 pthread_mutex_unlock() Note over C: ⏰ 被唤醒, 自动重新获得 mutex Note over C: 🔄 while(size==0) 再检查<br/>防 spurious wakeup C->>Q: 📤 event = buffer[head]<br/>head = (head+1) % MAX<br/>size-- C->>NF: 📢 pthread_cond_signal(not_full) C->>M: 🔓 pthread_mutex_unlock() Note over C: 🎯 handle_event → handlers[type](e) Note over C: 🔁 回到 while 顶部

队列满时的反压

sequenceDiagram box rgb(42,84,122) 生产者 participant P as 生产者线程 end box rgb(231,111,81) 同步原语 participant M as mutex participant Q as queue participant NF as cond not_full end box rgb(45,106,79) 消费者 participant C as event_loop_thread end P->>M: 🔒 lock() Note over P: size==MAX, 队列满 P->>NF: 😴 wait(not_full, mutex) Note over P: ⚠️ 释放 mutex 并挂起 C->>M: 🔒 lock() C->>Q: 📤 pop 事件, size-- C->>NF: 📢 signal(not_full) C->>M: 🔓 unlock() Note over P: ⏰ 被唤醒, 重获 mutex Note over P: 🔄 while(size==MAX) 再检查 P->>Q: 📝 push 事件, size++ P->>M: 🔓 unlock()

event loop 主循环

flowchart TD A["queue_pop(q, &e)"] A1["🔒 lock(mutex)"] A2["😴 while(size==0): wait(not_empty)"] A3["📤 取出 buffer[head], size--"] A4["📢 signal(not_full)"] A5["🔓 unlock(mutex)"] B{e.type == QUIT?} C["📢 queue_push(q, &e)\n转发 QUIT"] D["🛑 break"] E["🎯 handle_event(&e)"] E1["查 handlers[e.type]"] E2["调用回调函数"] A --> A1 --> A2 --> A3 --> A4 --> A5 A5 --> B B -- Yes --> C --> D B -- No --> E --> E1 --> E2 --> A style A fill:#264653,color:#fff,stroke:#1d3557 style A1 fill:#e76f51,color:#fff,stroke:#c1440e style A2 fill:#e9c46a,color:#000,stroke:#f4a261 style A3 fill:#2a9d8f,color:#fff,stroke:#21867a style A4 fill:#e76f51,color:#fff,stroke:#c1440e style A5 fill:#e76f51,color:#fff,stroke:#c1440e style B fill:#f4a261,color:#000,stroke:#e76f51 style C fill:#264653,color:#fff,stroke:#1d3557 style D fill:#c1121f,color:#fff,stroke:#780000 style E fill:#2d6a4f,color:#fff,stroke:#1b4332 style E1 fill:#2d6a4f,color:#fff,stroke:#1b4332 style E2 fill:#2d6a4f,color:#fff,stroke:#1b4332

颜色含义

颜色 含义
🟧 橙/红 mutex 操作 (lock / unlock / signal)
🟨 黄 条件等待 (cond_wait)
🟩 绿 事件分发 (handle_event / 回调)
🟦 蓝 队列数据操作 (push / pop)

堵塞改进 - 增加线程池

 while (running) {
     queue_pop(q, &e);
     if (e.type == EVENT_QUIT) { ... break; }
-    handle_event(&e);
+    thread_pool_submit(&pool, &e);  // 异步派发,不阻塞
 }
+ thread_pool_destroy(&pool);  // loop 退出后等待 worker 完成

关键点

这个 event loop 的核心就是一个基于 mutex + 条件变量的有锁阻塞队列。

本质上整个模型可以归结为:

loop 线程阻塞在 queue_pop (锁 + cond_wait)
→ 有事件时被唤醒 (锁 + cond_signal/broadcast)
→ 取出事件 → 派发
→ 回去继续阻塞

问题 解法
loop 空闲时如何不占 CPU wait(not_empty) 挂起线程,由 push 端 broadcast 唤醒
队列满时生产者怎么办 wait(not_full) 挂起,由 pop 端 signal 唤醒
为什么用 while 不用 if pthread 允许 spurious wakeup,醒来后必须重新检查条件
wait 时 mutex 怎么办 cond_wait 原子地释放 mutex 并挂起,被唤醒时自动重新加锁
为什么 not_empty 用 broadcast 多消费者需唤醒所有等待者
为什么 not_full 用 signal pop 只腾出一个位置,唤醒一个生产者即可
(改进) 这里是单线程eventloop+单线程handler会堵塞loop,如何做多线程 新增线程池,然后将handle_event改为提交到线程池执行即可达到不堵塞loop的需求
(改进) 用无锁队列实现呢 推荐eventfd+环形队列,利用内核的eventfd read堵塞完成调度

应用场景

  • WEB服务器的路由组件(nginx/nodejs/AI Agent)
  • 异步的内存数据处理(视频数据处理)
  • GUI图形界面架构(Windows/QT/JWT/JavaFX/)
  • 云服务架构的消息队列(基于Kafka/RabbitMQ的微服务架构)