今天是学习嵌入式的第33天
进程间通信 IPC
线程之间通信简单,直接读写全局共享变量就行。但是进程之间内存完全隔离,互相看不见对方的数据,必须靠操作系统提供的IPC手段传递数据。
常见方式:管道、信号、消息队列、共享内存、信号量。
1.管道
无名管道 pipe()
只能给有血缘关系进程用,比如父子进程。
调用pipe(fd),得到两个文件描述符 fd[0]读端,fd[1]写端。
子进程fork之后,父子进程都持有这两个文件描述符。一个往fd[1]写数据,另一个从fd[0]读数据。
半双工:单向数据流,数据只能从写端流向读端。
管道行为特点:
1. 管道里面有数据,read直接读;没数据,read阻塞睡觉。
2. 如果所有写端全部关闭,read读完现有数据直接返回0,不会阻塞。
3. 如果所有读端全部关闭,再往管道write写,直接触发管道破裂,进程收到信号直接退出。
有名管道 mkfifo
又叫FIFO文件,在磁盘生成一个特殊文件,没有血缘关系进程也能通信。
注意:open打开有名管道的时候,读和写必须两边都到位,open才会成功,否则程序阻塞卡住。
2.信号
信号就是操作系统发给进程的简短通知,用来告诉进程发生某个事件。比如按Ctrl+C就是发送SIGINT信号。
进程收到信号有三种处理方式:
1. 默认处理:系统自带行为,大部分信号会直接杀死程序。
2. 忽略信号,收到啥也不干。9号SIGKILL、19号SIGSTOP这俩信号不能忽略,强制杀死/暂停。
3. 捕获信号:收到信号就执行我们自己写的信号处理函数。
相关函数:
1. signal():简单设置信号处理函数。
2. kill(pid,信号编号):给指定pid进程发送信号。
3. alarm(seconds):几秒之后,给自己进程发送SIGALRM闹钟信号。
4. pause():让进程睡觉,直到收到一个信号才唤醒继续跑。
3.消息队列
内核开辟的消息缓冲区,多个进程可以往队列丢消息包,也可以按类型读取消息包。
命令ipcs查看IPC对象,ipcrm删除。
ftok:根据文件路径+一个小数字,生成唯一key值,用这个key来创建消息队列。
msgget:根据key拿到消息队列ID。
msgsnd:发送消息。
msgrcv:接收消息,可以指定只读取某一类消息。
msgctl:删除消息队列,获取消息队列状态。
优点:可以按消息类型筛选读取;缺点:拷贝数据,有开销。
4.共享内存(IPC里面速度最快)
内核开辟一块物理内存,多个进程把这块内存映射到自己的虚拟地址空间。所有进程直接读写同一块内存,数据不需要在内核和用户空间来回拷贝,速度拉满。
注意!共享内存本身不带同步保护!多进程同时读写会乱,必须搭配信号量/互斥锁控制访问时序。
流程:
1.shmget:创建共享内存,拿到shmid;
2.shmat:把共享内存映射到当前进程虚拟地址,得到内存首地址,之后直接指针读写;
3.shmdt:解除映射,断开进程和这块内存的联系;
4.shmctl:销毁共享内存。
5.信号灯集(System V信号量)
跟线程信号量用途差不多,但是可以跨进程使用。semget创建信号灯集合,semop执行P/V操作(申请释放资源),semctl初始化值、删除信号灯。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)