| 上一篇 | 下一篇 |
|---|---|
| 如何判断一个浮点型运算结果是否为整数 |
目 录
- 生产者-消费者模型
- 1)定义
- 2)核心同步问题
- 3)实现方式
- 3.1)基于信号量的经典方案
- 3.2)在 RTOS 中(如 FreeRTOS)
- 4)实际工作中常见的应用场景
- 5)总结
生产者-消费者模型
1)定义
生产者-消费者模型 是并发编程中最经典的设计模式之一,用于解决多线程/多进程之间数据传递与协作的问题。
- 生产者(Producer):负责生成数据(比如传感器采集、网络接收、文件读取)。
- 消费者(Consumer):负责处理数据(比如计算、显示、存储、转发)。
- 共享缓冲区(Buffer):一个固定大小的队列或环形缓冲区,生产者把数据放进去,消费者从里面取出来。
三者关系:[生产者] —(写入)—> [共享缓冲区] —(读取)—> [消费者]。
为什么需要这个模型?
| 好处 | 说明 |
|---|---|
| 解耦 | 生产者和消费者互不依赖,可以独立变化 |
| 平衡速度差异 | 生产者快、消费者慢时,数据暂存缓冲区,不会丢失或阻塞 |
| 异步处理 | 生产者在产生数据后不必等消费者处理完,可以立刻去做下一件事 |
| 支持并发 | 多个生产者和多个消费者可以同时工作 |
2)核心同步问题
共享缓冲区是临界资源,需要解决两个问题:
| 问题 | 描述 | 典型解决方式 |
|---|---|---|
| 互斥 | 同一时刻只能有一个线程修改缓冲区 | 互斥锁(mutex) |
| 同步 | 缓冲区满时生产者必须等待,缓冲区空时消费者必须等待 | 信号量(semaphore) |
3)实现方式
3.1)基于信号量的经典方案
// 假设有一个长度为 N 的环形缓冲区sem_tempty_slots;// 初始值为 N(空位数)sem_tfilled_slots;// 初始值为 0(已填数据数)mutex_tbuffer_mutex;// 保护缓冲区操作voidproducer(){while(1){item=produce_item();sem_wait(&empty_slots);// 等有空位mutex_lock(&buffer_mutex);insert_item(item);// 放入缓冲区mutex_unlock(&buffer_mutex);sem_post(&filled_slots);// 通知有新数据}}voidconsumer(){while(1){sem_wait(&filled_slots);// 等有数据mutex_lock(&buffer_mutex);item=remove_item();// 取出缓冲区mutex_unlock(&buffer_mutex);sem_post(&empty_slots);// 通知有空位consume_item(item);}}3.2)在 RTOS 中(如 FreeRTOS)
通常会用消息队列(Queue)直接实现,队列本身已经内置了互斥和同步机制:
QueueHandle_t xQueue=xQueueCreate(QUEUE_LENGTH,sizeof(Data_t));// 生产者voidvProducerTask(void*pvParameters){Data_t data;// ... 生成数据xQueueSend(xQueue,&data,portMAX_DELAY);}// 消费者voidvConsumerTask(void*pvParameters){Data_t data;xQueueReceive(xQueue,&data,portMAX_DELAY);// ... 处理数据}4)实际工作中常见的应用场景
| 场景 | 生产者 | 消费者 | 缓冲区 |
|---|---|---|---|
| 日志系统 | 各个业务线程产生日志 | 单独的日志线程写入文件 | 无锁环形缓冲区 |
| 串口通信 | 串口接收中断(ISR) | 数据解析线程 | RingBuffer |
| 网络包处理 | 网卡驱动接收数据 | 协议栈线程(LwIP) | pbuf 链表 / 队列 |
| 传感器数据采集 | 定时器中断采集 ADC | 数据处理/上传线程 | 双缓冲或队列 |
5)总结
生产者消费者模型就是通过一个共享的缓冲区,把“生产数据”和“消费数据”两个动作分开,让它们可以并发、异步地执行,并利用互斥和同步机制保证数据安全与流程协调。