当前位置:首页 > 嵌入式 > 嵌入式分享
[导读]嵌入式Linux系统中,多进程间的数据交互是常见需求——采集进程需要把传感器数据传给显示进程,控制进程需要从决策进程获取指令。管道和消息队列虽然方便,但涉及内核缓冲区拷贝,延迟较高。共享内存是所有IPC中延迟最低的方式,因为它让两个进程直接读写同一块物理内存,零拷贝。但共享内存本身不提供同步机制,需要搭配信号量来避免竞态条件。本文以一个“采集→处理→显示”的三进程模型为例,展示共享内存+信号量的实战用法。


嵌入式Linux系统中,多进程间的数据交互是常见需求——采集进程需要把传感器数据传给显示进程,控制进程需要从决策进程获取指令。管道和消息队列虽然方便,但涉及内核缓冲区拷贝,延迟较高。共享内存是所有IPC中延迟最低的方式,因为它让两个进程直接读写同一块物理内存,零拷贝。但共享内存本身不提供同步机制,需要搭配信号量来避免竞态条件。本文以一个“采集→处理→显示”的三进程模型为例,展示共享内存+信号量的实战用法。

一、共享内存的创建与映射

使用POSIX共享内存(shm_open+mmap)或System V共享内存(shmget+shmat)。POSIX接口更现代,推荐使用。

#include <sys/mman.h>

#include <fcntl.h>

#include <semaphore.h>

#include <unistd.h>


#define SHM_NAME "/sensor_shm"

#define DATA_SIZE 4096


typedef struct {

   float temperature;

   float pressure;

   uint32_t timestamp;

   uint8_t valid;

} sensor_data_t;


// 创建/打开共享内存

int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);

ftruncate(shm_fd, DATA_SIZE);

sensor_data_t *shared_data = (sensor_data_t *)mmap(NULL, DATA_SIZE,

   PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);

close(shm_fd);

每个进程调用相同的shm_open+mmap,即可获得指向同一块物理内存的指针。

二、信号量的同步

使用POSIX有名信号量(sem_open)实现互斥和同步。需要两个信号量:一个用于互斥访问共享内存(mutex),一个用于通知数据就绪(ready)。

// 创建信号量

sem_t *mutex = sem_open("/sem_mutex", O_CREAT, 0666, 1);  // 初始值1

sem_t *ready = sem_open("/sem_ready", O_CREAT, 0666, 0);  // 初始值0


// 写入进程(采集)

void collector_task(void) {

   while (1) {

       sensor_data_t data = read_sensor();

       sem_wait(mutex);                     // 请求互斥锁

       memcpy(shared_data, &data, sizeof(data));

       shared_data->valid = 1;

       sem_post(mutex);                     // 释放互斥锁

       sem_post(ready);                     // 通知读取进程

       sleep(1);

   }

}


// 读取进程(处理/显示)

void processor_task(void) {

   sensor_data_t local;

   while (1) {

       sem_wait(ready);                     // 等待数据就绪

       sem_wait(mutex);

       memcpy(&local, shared_data, sizeof(local));

       sem_post(mutex);

       process_and_display(&local);

   }

}

sem_wait阻塞直到信号量值大于0,然后减1;sem_post将信号量加1。mutex保证同一时刻只有一个进程操作共享内存,ready实现生产-消费同步。

三、低延迟的关键

零拷贝:数据直接从共享内存读取,无需经过内核缓冲区。

用户态同步:信号量操作在用户态完成(基于futex),不陷入内核(除非竞争)。

缓存友好:将共享数据结构设计为cache line对齐,避免伪共享。

// 对齐到64字节(常见cache line大小)

typedef struct __attribute__((aligned(64))) {

   float temperature;

   float pressure;

   uint32_t timestamp;

   uint8_t valid;

   uint8_t pad[3];  // 填充到64字节

} sensor_data_t;

四、清理与异常处理

进程退出时必须释放资源,否则共享内存和信号量会残留。

void cleanup(void) {

   munmap(shared_data, DATA_SIZE);

   shm_unlink(SHM_NAME);       // 删除共享内存对象

   sem_close(mutex);

   sem_close(ready);

   sem_unlink("/sem_mutex");

   sem_unlink("/sem_ready");

}

通常由最后一个退出的进程负责shm_unlink和sem_unlink。

五、三个翻车高发点

忘记初始化共享内存:mmap后共享内存内容是随机的,写入进程必须先初始化有效字段(如valid=0),读取进程应检查valid标志。

信号量死锁:如果某个进程在持有mutex时崩溃,其他进程会永久阻塞。解决方案是使用sem_timedwait设置超时,超时后重建信号量。

多核缓存一致性问题:ARM多核处理器中,一个核写入共享内存,另一个核可能读到旧值。使用__sync_synchronize()或C11原子操作确保可见性。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

在GD32系列MCU运行FreeRTOS、RT-Thread等实时操作系统时,多任务并发访问共享资源(如UART、SPI总线、全局缓冲区)是常态。信号量(Semaphore)与互斥量(Mutex)是两种最常用的同步机制,...

关键字: 信号量 互斥量 GD32

互斥量和信号量长得像,用法像,连API都像——但它们的设计意图完全相反。互斥量管的是"谁能进这扇门",信号量管的是"还剩几张票"。用错了,轻则优先级反转死锁,重则整个系统卡死。90...

关键字: 互斥量 信号量

μC/OS-II是一个完整的,可移植、可固化、可裁减的占先式实时多任务内核,它功能强大,支持56个用户任务,支持信号量、邮箱、消息队列等多种常用的进程间通信机制。

关键字: 信号量 邮箱

进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。

关键字: 进程间通信 通信 共享内存

摘要:随着我国智能电网的快速发展,传统采集设备已无法完全满足当前需求。配电台区是营销与生产的交汇点,传统模式下,营销与生产双方需要在台区侧分别安装集中器和配变终端(TTU)两种设备,但仍存在诸多问题。在此背景下,融合了I...

关键字: 能源控制器 信号量 死锁

衰落效应是影响无线通信质量的主要因素之一。其中的快衰落深度可达30~40dB,如果想利用加大发射功率、增加天线尺寸和高度等方法来克服这种深衰落是不现实的,而且会造成对其它电台的干扰。而采用分集方法即在若干个支路上接收相互...

关键字: 分集技术 信号量 衰减

摘要:阐述了一种基于GPRS和嵌入式Linux的远程图像监控系统设计和实现方法。该系统主要由嵌入式视频采集终端 和监控中心服务器组成。其中,嵌入式视频采集终端主要由摄像头视频采集模块、ARM模块、SIM900模块组成,监...

关键字: 通用分组无线业务 实时图像采集 多线程 信号量

FreeRTOS的信号量包括二进制信号量、计数信号量、互斥信号量(以后简称互斥量)和递归互斥信号量(以后简称递归互斥量)。

关键字: FreeRTOS 信号量分析 信号量

 1 BOOL ReleaseSemaphore( 2  HANDLE hSemaphore, // 信号量句柄 3  LONG lReleaseCount, // 计数递增数量 4  LPLONG 

关键字: 信号量

 1 BOOL ReleaseSemaphore( 2  HANDLE hSemaphore, // 信号量句柄 3  LONG lReleaseCount, // 计数递增数量 4  LPLONG 

关键字: c++ mfc 信号量 semaphore csemaphore类
关闭