1. 多线程同步:为什么我们需要同步机制?
在RT-Thread这样的实时操作系统中,多线程环境是常态。想象一下,你和几个同事共享一个办公室打印机,如果大家同时点击打印,结果会怎样?要么文件混在一起,要么打印机直接卡死。这就是多线程环境下的典型问题:竞态条件和数据不一致。
我在实际项目中就遇到过这样的坑:两个线程同时操作同一个全局变量,一个负责累加,一个负责显示。理论上应该显示连续递增的数字,结果屏幕上时不时跳出一些莫名其妙的值。这就是因为没有做好同步,两个线程"撞车"了。
RT-Thread提供了多种同步机制,最常用的就是信号量、互斥量和事件集。它们各有特点,就像不同的交通管制方式:信号量像是红绿灯,控制流量;互斥量像是厕所的门锁,保证独占使用;事件集则像是多条件触发器,可以等待多个条件同时满足。
2. 信号量:像红绿灯一样的流量控制器
2.1 信号量的工作原理
信号量本质上是一个计数器,用来控制对共享资源的访问。你可以把它想象成游乐园的入场券:总共有N张票,每个线程需要一张票才能进入"游乐设施"(临界区)。票发完了,后来的线程就得排队等待。
RT-Thread中信号量的数据结构很简单:
struct rt_semaphore {
struct rt_ipc_object parent;
rt_uint16_t value; // 当前计数值
rt_uint16_t reserved; // 预留字段
};
我刚开始用信号量时,经常混淆value的初始值设置。后来总结出一个经验法则:保护单个资源用1,管理多个资源用N,同步线程执行用0。
2.2 信号量的实际应用
来看一个我经常在项目中用的生产者-消费者模式:
#include <rtthread.h>
#define DBG_TAG "sem_demo"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
rt_sem_t produce_sem, consume_sem;
int buffer[10];
int count = 0;
void producer_entry(void *parameter)
{
while (1) {
// 等待可以生产的信号
rt_sem_take(produce_sem, RT_WAITING_FOREVER);
// 生产数据
buffer[count] = count;
count++;
rt_kprintf("Produced: %d\n", count);
// 通知消费者
rt_sem_release(consume_sem);
rt_thread_mdelay(100);
}
}
void consumer_entry(void *parameter)
{
while (1) {
// 等待消费信号
rt_sem_take(consume_sem, RT_WAITING_FOREVER);
// 消费数据
count--;
rt_kprintf("Consumed: %d\n", count);
// 通知生产者
rt_sem_release(produce_sem);
rt_thread_mdelay(150);
}
}
int semaphore_demo(void)
{
// 创建信号量:生产者初始可以生产10个,消费者初始不能消费
produce_sem = rt_sem_create("produce", 10, RT_IPC_FLAG_FIFO);
consume_sem = rt_sem_cre


3066

被折叠的 条评论
为什么被折叠?



