ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux学习日记:进程通信(IPC)机制

Linux学习日记:进程通信(IPC)机制 进程间通信上IPC总共五种分别是管道、信号量、消息队列、共享内存、套接字1.管道管道又分为命名管道和匿名管道作用比方说我现在想在a进程与b进程之间通信希望在a进程写入数据b进程读取数据这时候就可以使用管道。那去使用.txt文件不是一样可以做到吗a进程在.txt文件写入内容b进程在.txt文件读取内容。是的使用纯文本文档一样可以做到但是管道的效率远超文件因为纯文本文档的写入与读取需要使用I/O设备而写入管道的数据会存放在内存中。命名管道创建命名管道使用mkfifo文件名删除方法与其他文件也一致使用示例a.c文件→b.c文件→很简单的两串代码主要还是open()/close()和write()/read()函数能否熟练使用那么此时只编译运行a.c发现程序直接阻塞住了甚至连fd的值都没有打印出来同理只运行b.c也是阻塞状态只有当两个进程同时运行时此时fd的值才能正常打出此时给a进程写入数据→此时两个进程同时结束可见通信最少必须在两个进程之间完成同时管道也是最基础的IPC机制若是改成循环即进程间多次发生通信a.c b.c主要注意循环终止条件当管道空时读端会阻塞管道满时写段会阻塞。写段先关闭读段read()返回值0读段先关闭写段write()会触发信号SIGPIPE13程序退出管道文件不占用内存只是一个接口实际上的内容写在内存开辟的一块空间上匿名管道匿名管道主要用于父子进程之间的通信它不需要先创建文件而是直接在代码中通过函数创建匿名管道pipe()函数创建匿名管道成功返回0失败返回-1参数为数组其中pipefd[0] 代表读端读权限。pipefd[1]代表写端写权限以下为示例若是在父子进程中使用#include unistd.h int main() { int fd[2]; pipe(fd); // 创建管道fd[0]读端fd[1]写端 if (fork() 0) { // 子进程 close(fd[0]); // 关闭读端 write(fd[1], Hello, 6); } else { // 父进程 close(fd[1]); // 关闭写端 char buf[10]; read(fd[0], buf, 6); printf(Received: %s\n, buf); } }总结管道是一个半双工通信什么是半双工即两个进程只能由一个读取数据一个写入数据但是对哪边进行读取或写入不做要求而手机通信是全双工通信收音机是单工通信。命名管道可以在任意两个进程间通信匿名管道只能在父子进程之间通信管道本质上是内核维护的内存缓冲区。2.信号量信号量是一种用于进程/线程同步的机制它不仅仅用于进程间通信更核心的作用是控制多个进程/线程对共享资源的访问。信号量的值0123都可以需要多少信号量由程序员自己来决定p操作等待对信号量减一若信号量的值为0则阻塞v操作释放若有进程此时在等待则唤醒等待进程否则信号量1想象一个停车场信号量的值 停车场的空位数量。P操作(等待) 一辆车进入停车场。空位减一。如果没有空位车子就必须等待。V操作(发送) 一辆车离开停车场。空位加一。如果有车在等待就放一辆车进来。临界资源同一时刻只允许一个进程访问的资源临界区访问临界资源的代码段信号量函数#include sys/sem.h int semget(key_t key, int nsems, int semflg);参数key_t key唯一唯一标识信号量集的键值。可以理解为同一个门牌号只要门牌号一样就是同一间房间不需要特定的门牌号。参数int nsems信号量个数想定义几个信号量就定义几个。参数int semflg权限标志和创建选项的组合权限位与文件权限类似0600创建选项IPC_CREAT如果不存在则创建如果已存在则忽略IPC_EXCL与IPC_CREAT一起使用如果已存在则失败返回值创建成功返回信号量集的标识符非负整数失败返回-1int semctl(int semid, int semnum, int cmd, ...);参数int semid由函数semget()返回的信号量集参数int semnum信号量在集合中的索引类似数组下标例如创建了两个信号量则第一个信号量索引为0第二个信号量索引为1以此类推参数int cmd要执行的控制命令。常用命令IPC_RMID立即删除信号量集SETVAL设置单个信号量的值GETVAL获取单个信号量的值SETALL设置所有信号量的值GETALL获取所有信号量的值IPC_STAT获取信号量集的状态信息第四个参数...可变参数通过自己定义的联合体union semun来输入union semun { int val; // SETVAL 用的值 struct semid_ds *buf; // IPC_STAT, IPC_SET 用的缓冲区 unsigned short *array; // SETALL, GETALL 用的数组 struct seminfo *__buf; // IPC_INFO 用的缓冲区Linux特有 };int semop(int semid, struct sembuf *sops, size_t nsops);参数int semid由函数semget()返回的信号量集参数struct sembuf* sops指向操作数组的指针其实就是指向一个结构体的指针不知道为啥非要这样说...参数size_t nsops操作数组的操作个数sembuf结构体struct sembuf { unsigned short sem_num; // 信号量在集合中的索引 short sem_op; // 操作类型 short sem_flg; // 操作标志 };结构体参数unsigned short sem_num信号量在集合中的索引同上类似数组下标结构体参数short sem_op赋值-1为p操作1为v操作结构体参数short sem_flg通常填写SEM_UNDO进程退出时自动撤销操作防止死锁或0默认阻塞行为此时存在两个进程text和tmp代码如下tmp.c text.c此时同时运行这两个程序放在后台可一起运行→会发现这两个进程同时混在一起运行无法做到一个进程运行完一次循环另一个进程再去运行。通过对上面三个函数进行封装得到自己的信号量函数sem_init()sem_p()sem_v()sem_destroy()此时再对text进程与tmp进程使用信号量进行控制tmp.c text.c运行结果总结信号量是一个功能强大的同步原语其核心是一个受保护的整型变量和两个原子操作P 和 V。它通过控制进程的等待和唤醒来协调对共享资源的访问。个人小结管道这里倒是通俗易懂信号量的接口实在是太多了...真的就是只能理解理解原理了联合体需要自己编写结构体需要记还有各种特殊参数QAQ。真的不好记进程间通信上课还因为前一天晚上熬夜导致没有好好听课现在补回放只感觉路漫漫其修远兮啊。
返回列表