Linux进程间通信
【Linux】进程间通信
1. 通信
通信概念:两个或者多个进程实现 数据 层面的交互
因为进程独立性的存在,导致进程通信的成本比较高
进程间通信的本质 :必须让不同的进程看到同一份”资源”——特定形式的内存空间。
这个”资源”谁提供?一般是 操作系统 ,
为什么不是我们两个进程中的一个呢?假设一个进程提供,这个资源属于谁?这个进程独有,破坏进程独立性。
“资源”从创建,使用,释放,都是使用系统调用接口!
基于文件级别的通信方式——–管道
进程间通信目的:
数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
2. 匿名管道
2.1 匿名管道的原理
管道就是文件
现在还要一个问题。
如果父进程只是以写或读的形式打开文件,那么子进程也只能是以写或读的形式打开文件,所以父子只能同时读或写。但是我们需要父写子读 或 父读子写。那么只能如下操作:
真正的管道通信原理:
也说明了管道只能进行单向通信。
如果我要进行双向通信呢?使用多个管道
如果没有任何关系,可以用我们刚刚讲的原理进行通信呢?不能
必须是父子关系,兄弟关系,爷孙关系…——–血缘关系,常用于父子
因为管道的内存级文件是匿名的,所以叫做匿名管道‘
2.2 匿名管道的有关代码编写
2.2.1 匿名管道代码编写
管道的特征:
- 具有血缘关系的进程进行进程间通信
- 管道只能单向通信
- 父子进程是会进程协同的,同步与互斥的——保护管道文件的数据安全
- 管道是面向字节流的
- 管道是基于文件的,而文件的生命周期是随 进程 的!
代码gitee链接:
管道的4种情况:
1.读写端正常,管道如果为空,读端就要阻塞
2.读写端正常,管道如果被写满,写端就要阻塞
3.读嘴正常读,写端关闭,读一段时间后,读端就会读到0,表明读到了文件(pipe)结尾,不会被阻塞
- 写端是正常写入,读端关闭了。操作系统就要杀掉正在写入的进程。如何干掉? 通过信号杀掉 。杀掉因为操作系统是不会做,低效,浪费等类似的工作的。
通过13号信号—–
SIGPIPE
杀掉进程
2.2.2 进程池代码
gitee代码:
3. 命名管道
3.1 创建命名管道的函数
创建命名管道的函数:
3.2 命名管道的原理
具有血缘关系的进程使用匿名管道,没有血缘关系的进程则使用命名管道。
如果两个不同的进程打开同一个文件的时候,在内核中,操作系统只会打开一个文件。
因为该管道文件不需要刷盘,所以直接创建内存级文件。
如何打开同一个文件,文件的文件名+路径相同即可。
3.3 命名管道代码的编写
gitee链接:
内含日志代码编写
4. system V共享内存
4.1 system V共享内存的原理
再次强调:进程间通信的原理是让进程看到同一份资源
如果要申请共享内存、释放共享内存、关联、去关联—–这些操作都是进程直接做的吗?不是。直接由操作系统来做。
需求方—> 系统调用 —> 执行方
4.2 相关函数
4.2.1 shmget 函数
作用:为共享内存申请空间
4.2.2 ftok函数
作用:用pathname和proj_id确定一个key
- key是一个数字,这个数字是几,不重要。关键在于它必须在内核中具有唯一性,能够让不同的进程进行唯一性标识
- 第一个进程可以通过key创建共享内存,第二个之后的进程,只要拿着同一个key就可以和第一个进程看到同一个共享内存了!
- 对于一个已经创建好的共享内存,key在哪?key在共享内存的描述对象中!
- 该函数使
key
的矛盾冲突较小 - 当路径不存在时,key就会返回-1;当key与系统中的共享内存相同时,就需要更改pathname或proj_id;
4.2.3 查看和删除共享内存
共享内存的生命周期是随内核的!
用户不主动关闭,共享内存会一直存在。
除非内核重启(用户释放)
key:操作系统内标定唯一性
shmid:只在你的进程内,用来表示资源的唯一性!
4.2.4 shmat 函数
4.2.5 shmctl 函数
作用:删除共享内存
4.3 共享内存的性质
- 共享内存没有同步互斥之类的保护机制
- 共享内存是所有的进程间通信中,速度最快的!因为拷贝少,管道要拷贝2次,共享内存1次也不用
- 共享内存内部的数据,由用户自己维护!
4.4 共享内存代码编写
链接如下:
,其中利用了管道解决了共享内存同步问题。
5. 消息队列
5.1 消息队列的原理
6. IPC在内核中的数据结构设计
使用 C的方式继承 的方法。