进程间通信

1. 进程间通信:操作系统为进程之间提供的几种通信方式。

1.1 进程之间不能直接通信的原因:每个进程都有自己独立的虚拟地址空间,操作的都是自己的地址,因此进程之间具有独立性,无法直接通信,因此才需要操作系统提供通信方式。
1.2 操作系统提供通信方式:实际上是提供一块公共的媒介,能够让多个进程都能访问到这个媒介实现通信。
1.3 通信方式
因为通信场景不同,因此操作系统也提供多种方式供用户选择:数据传输(管道通信,消息队列),数据共享(共享内存),进程控制(信号量)
1.4进程间通信目的
数据传输:一个进程需要将它的数据发送给另一个进程。
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止 时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另 一个进程的所有陷入和异常,并能够及时知道它的状态改变。

2.管道通信(一种半双工通信)

2.1 管道通信的本质
本质:操作系统在内核中创建的一块缓冲区,多个进程通过访问同一块缓冲区就可以实现通信
2.2 管道种类:匿名管道/命令管道
1.匿名管道:内核中的缓冲区没有明确的标识
管道的创建:一个进程创建一个管道,操作系统为了让进程能够对管道进行读写数据,因此向外返回了两个操作句柄(文件描述符),一个用于读,一个用于写,通过在进程中创建管道创建之后,在创建一个子进程,这个子进程就能访问到管道了,因此子进程复制了父进程,可以通过复制的两个操作句柄进而对管道进行操作,并且父子进程操作的是同一个管道。

int pipe(int pipefd[2]);
//pipefd[0]用于向管道读取数据
//pipefd[1]用于向管道写入数据

管道读写特性:
(1)若管道中没有数据,则read读取会阻塞;若管道中缓冲区已经写满,则write会阻塞
(2)若管道所有写端被关闭,则read读取完管道中的数据之后,就会返回0,不在阻塞—read返回0主要用于表达管道所有写端已关闭
(3)若管道所有读端被关闭,则write继续写入数据会触发异常,导致进程退出
匿名管道的特性:匿名管道只能用于具有亲缘关系的进程间通信
2**.命名管道**:有名字的管道—内核中管道缓冲区有自己的标识符
命名管道的特性:可以用于同一主机上的任意进程间通信
命名管道标识符:是一个可见于文件系统的特殊管道文件

int mkfifo(const char *filename,mode_t maode)
//mkfifo创建一个命名管道

打开特性:
(1)若管道已只读打开,则会阻塞,直到管道被以写的方式打开位置
(2)若管道已只写打开,则会阻塞,直到管道被以读的方式打开位置
2.3 管道符的实现
| 连接两个命令,将前面命令的输出结果当做后面命令的输入进行处理

ps -ef | grep ssh
//ps将结果输出到标准输出;grep从标准输出读取数据进行字符串匹配

创建进程1运行ps;创建进程2运行grep,在创建进程之前创建一个管道实现进程1与进程2之间的通信
如何让进程1将ps结果不在打印而是写入管道—将标准输出1重定向到管道写入端
如何让进程2将grep不再从标准输出读取而是从管道读取----将标准输入0重定向到管道读取端
2.4 管道的特性
1.管道是一个半双工通信
2.管道自带同步与互斥
互斥:管道中的用户操作的数据大小不超过PIPE_BUF = 4096大小,则保证这次操作原子性
同步:若管道没有数据则read阻塞;若管道写满则write阻塞
同步:通过一种条件判断,保证多个进程对临界资源的访问时序合理性
互斥:通过同一时间只有一个进程能够访问临界资源,保证临近资源操作的安全性
原子性:操作要不然不完成(过程不可被打断),要不然就不做
3.提供字节流服务:安全的,有序的数据传输,数据的传输读写比较灵活
4.生命周期随进程:打开管道的进程若都退出,则管道会被释放

3. 共享内存

3.1 概念
共享内存:将同一块物理内存映射到进程各自的虚拟地址空间中就可以是实现数据共享,因为都可以通过自己的虚拟地址空间进行访问
3.2 特性
(1)最快的进程间通讯方式
原因:因为共享内存直接通过虚拟地址访问物理内存,进行数据共享,而其他通信方式,需要先将数据拷贝入内核,再从内核拷贝出来,才能实现通信,因此共享内存的通信相较于其他方式少了两次数据拷贝操作,所以速度最快
(2)生命周期随内核
(3)共享内存的操作并不安全(多个进程同时操作有可能会造成数据二义)
3.3 共享内存的代码操作
(1)创建/打开共享内存—若共享内存创建了,则直接打开,打开时并不会清空内存数据
函数:int shmget(key_t key,size_t size,int shmflg);
功能:用来创建共享内存
参数:
key:是共享内存的标识符—多个进程就是通过同一个标识符才能访问同一块共享内存 IPC_PRIVATE—私有只能用于具有亲缘关系的进程间通信
size:要创建的共享内存大小–一内存也为单位
shmflg:
IPC_CREAT–共享内存不存在则创建,存在则打开
IPC_EXCL–与同时使用,不存在则创建,存在则报错
返回值:共享内存在代码中的操作句柄
(2)将共享内存映射连接到进程的虚拟地址空间
函数:void *shmat(int shmid,const void *shmaddr,int shfig);
功能:将共享内存段连接到进程地址空间
参数:
shmid:创建共享内存时,返回的操作句柄
shmaddr:共享内存映射在虚拟空间中的首地址,通常置NULL,让操作系统来进行分配一个合适的地址
shmflg:在堆共享内存具用权限的情况下,可以设置在代码中的操作权限 SHM_RDONLY-则为只读(前提是具有共享内存的可读权限)
默认为0时,则为可读可写
返回值:返回共享内存在虚拟地址空间中实际映射的首地址,-1表示失败,而不是空。
(3)根据返回映射的首地址可以解除映射
函数:int shmdt(const void *shmaddr);
功能:将共享内存段与当前进程脱离
参数: shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除
(4)删除共享内存(只有当共享内存映射为0的时候,才会删除内存)
函数:int shmctl(int shmid,int cmd,struct shmid_ds *buf)----共享内存的信息获取/设置
功能:用于控制共享内存
参数:shmid:操作句柄
cmd:对共享内存向要进行的操作IPC_RMID-标记共享内存为将要销毁—实际销毁是在映射链接树为0的时候
buf:在设置/获取共享内存信息的时候,通过这个结构体返回数据或者设置新数据
返回值:成功返回0;失败返回-1

4.消息队列

4.1 概念:消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值特性方面 IPC资源必须删除,否则不会自动清除,除非重启,
4.2 本质:在操作系统内核中创建了一个优先级队列,多个进程间通过向队列中添加数据块或者获取数据块实现数据通信
struct msgbuf{type;data}—这个结构体由用户自己定义,因为操作系统无法决定数据的长度
4.3 特性
1.生命周期随内核
2.消息队列也是自带同步与互斥
3.消息队列所能存储的数据是有最大长度限制的

5.信号量

5.1 概念
信号量:本身并不是用于实现通信的,而是用于实现进程间同步与互斥的(保护进程间对临界资源进行访问时不会出现数据二义性)
同步:通过一定的条件判断,实现进程间符临界资源访问的时序合理性
互斥:通过同一时间的唯一访问,实现进程间对临界资源访问的安全性
临界资源:进程间都能访问到的资源
临界区:对临界资源进行操作的代码区域
5.2 本质
计数器+pcb等待队列—>使一个进程陷入休眠的接口/唤醒一个休眠进程的接口
计数器:统计资源的数量,通过数量判断当前的访问是否合理
5.3 信号量同步的实现:数据是资源,初始化的时候有多少数据资源,计数就会初始化为相应的数量
进程A获取数据资源,若计数器>0;表示有资源可以直接获取,计数器-1;若计数器<+0表示没有资源,则需要调用是一个进程陷入休眠的接口,让进程进行等待,计数器-1;进程B产生一个资源,判断若计数器<0,则调用唤醒一个休眠进程的接口即唤醒一个等待中进程A,计数器+1;若计数器>=0,则没有人等待,计数器直接+1;
5.4 信号量实现互斥:保证同一时间只有一个进程能够访问资源(保证最大计数小于1)
信号量本身是一个计数器,计数器为0的时候就会让继续访问资源的进行陷入等待,等待其他进程唤醒,若一个计数器的计数最大只有1,表示只有一个资源,只能一个进程去访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值