ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Zephyr应用: 11-Semaphore

2026/9/29 6:16:09 拓冰建站 浏览量
Zephyr应用: 11-Semaphore 第 11 课:Semaphore(信号量)摘要本课深入讲解 Zephyr RTOS 中线程同步的核心机制——Semaphore(信号量)。你将掌握二值信号量与计数信号量的区别,学会K_SEM_DEFINE()、k_sem_take()、k_sem_give()等核心 API,并通过生产者-消费者、GPIO 中断唤醒线程等实战示例,理解信号量在事件通知与资源计数中的典型应用,告别轮询带来的 CPU 浪费。学完本课,你就能在嵌入式多线程项目中正确选用信号量,为后续学习 Mutex 与 Message Queue(消息队列)打下坚实基础。关键词:Zephyr RTOS、Semaphore(信号量)、线程同步、Binary Semaphore(二值信号量)、Counting Semaphore(计数信号量)目标学会 Zephyr 中线程同步最重要的机制——Semaphore(信号量)。完成本课以后,你应该知道:什么是 SemaphoreBinary Semaphore(二值信号量)Counting Semaphore(计数信号量)k_sem_init()k_sem_take()k_sem_give()K_FOREVERK_NO_WAIT一、为什么需要 Semaphore?假设有两个线程。Thread A ↓ 采集ADC ↓ 处理完成Thread B ↓ 等待ADC完成 ↓ 发送数据如果没有同步:Thread B while(1){if(adc_ready)send();}这叫Polling(轮询)缺点:浪费CPU 延迟高 不优雅所以需要:Thread A 完成工作 ↓通知 Thread B这个通知就是:Semaphore二、Semaphore 工作原理可以理解成一个「令牌(token)」,用于控制对共享资源的访问。初始:Semaphore=0Thread B等待SemaphoreThread A完成工作 ↓ give SemaphoreSemaphore变成1Thread B立刻被唤醒。流程:Thread A give()│ ▼ Semaphore++ │ ▼ Thread B take()继续运行Thread Btake()继续运行 下面用时序图更直观地展示 `k_sem_give()` 唤醒线程的完整过程: ```mermaid sequenceDiagram participant A as Thread A participant S as Semaphore participant B as Thread B Note over B: 调用 k_sem_take() 等待 B-S: k_sem_take(my_sem, K_FOREVER) Note over S: 计数为 0,B 阻塞等待 A-S: k_sem_give(my_sem) Note over S: 计数 0 → 1 S--B: 唤醒等待中的线程 B B-S: k_sem_take() 获取令牌 Note over S: 计数 1 → 0 Note over B: 继续运行时序说明:线程 B 先调用k_sem_take()等待令牌,此时计数为 0,B 进入阻塞;线程 A 完成工作后调用k_sem_give(),信号量计数从 0 增加到 1,内核随即唤醒等待中的线程 B;B 被唤醒后通过k_sem_take()取走令牌,计数回到 0,B 继续执行后续逻辑。整个过程实现了「A 通知、B 等待」的线程同步。三、Binary Semaphore只有:0或者1类似:门关着0门打开1这是 RTOS 中最常见的同步方式。四、Counting Semaphore例如:最大值5Semaphore0↓1↓2↓3↓4↓5可以表示:资源数量。例如:USB Buffer 剩余5个每拿一个:take()↓4释放:give()↓5五、创建 SemaphoreZephyr:#includelt;zephyr/kernel.hgt;K_SEM_DEFINE(my_sem,0,1);解释:名字 my_sem初始值:0最大值:1所以:Binary Semaphore如果:K_SEM_DEFINE(my_sem, 0, 5);就是:Counting Semaphore六、动态初始化也可以:structk_semsem;k_sem_init(sem,0,1);参数:初值0最大值1七、等待 Semaphore线程等待:k_sem_take(my_sem,K_FOREVER);意思:一直等直到:别人give()也可以:k_sem_take(my_sem,K_SECONDS(2));等待:2秒超时:返回错误立即返回:k_sem_take(my_sem,K_NO_WAIT);如果没有:Semaphore立即失败。八、释放