进程间通信总结


什么是进程间通信? 
进程间通信指的是在进程之间进行数据的传输(信息交换)
为什么需要进程间通信?
对于操作系统来说无论是应用程序还是系统程序,都需要针对其中不同的功能创建不同的进程,但是因为进程具有独立性,每一个进程都有着独立的虚拟地址空间,不同的进程无法访问同一块空间,所以进程之间无法直接通信。因而引入了进程间通信。操作系统会根据不同的通信场景而提供不同的通信方式

进程间通信方式

管道

什么是管道?
管道是一种以字节为单位的基于连接的先进先出传输方式,将一个读进程和一个写进程连接起来,在这里两个进程之间共享一个通信文件,写进程将所需要写入的信息以字节流的方式流入管道中,读进程则从管道中接收数据,读进程读取了管道中的数据中,这部分数据就会被释放,所以管道也可以理解为一种循环队列,一端不停的进数据,另一端不停的出数据,数据被读取之后就从这块缓冲区出去
管道的本质
管道的本质就是内核中的一块缓冲区(一块有限的内存空间),让不同的进程访问到同一个管道,也就是说访问到同一块缓冲区(一块内存空间)来实现进程间通信。对于通信两端的进程来说,管道就是一个文件,并且是一种单独构成的文件系统与一般的文件不同,这也体现出了linux下一切皆文件的宗旨
管道分类
管道分为匿名管道pipe(缓冲区没有标识符)和命名管道fifo(缓冲区有标识符)
管道特点
1.管道是半双工通信(可以选择方向的单向传输方式)
2.如果管道中没有数据,那么调用read时会阻塞
3.如果管道中数据满了,那么调用write时会阻塞
4.如果管道的所有读端关闭,那么调用write会产生异常并退出当前进程
5.如果管道的所有写端关闭,那么调用read会继续读取管道中的数据,读取完毕之后不再阻塞并且返回0
6.管道自带同步与互斥
管道同步:管道中没有数据调用read阻塞,数据满了调用write阻塞,通过条件判断实现临界资源访问的合理性
管道互斥:管道的读写操作,当数据大小小于PIPE_BUF(4096字节)时保证操作的原子性,大于时不再保证
7.管道的声明周期随进程,所以进程退出之后,管道也就释放了

匿名管道

匿名管道也存在于内核中的一块缓冲区,但是缓冲区没有标识符,所以只能通过子进程复制父进程的方式获取到同一管道的操作句柄去访问同一管道,所以匿名管道只能用来实现具有亲缘关系(具有共同的祖先)的进程间通信
创建匿名管道

int pipe(int pipefd[2]);
//pipefd[2]:具有两个int型节点的数组首地址,接收创建管道返回的操作句柄
//pipefd[0]:用于从管道中读取数据
//pipefd[1]:用于向管道中写入数据

命名管道

和匿名管道一样也是存在于内核中的一块缓冲区,但是这块缓冲区具有标识符,这个标识符与磁盘上的一个索引点相对应,所以可用于主机上的任意进程间的通信,通过访问内存中的同一块缓冲区来实现不同进程间的通信
创建命名管道
1.在Linux下创建命名管道

mkfifo my_fifo

这个命令就是在当前的目录下面创建了一个叫做my_fifo的命名管道,当我们使用ls -p命令去查看文件的类型时,可以看到命名管道的对应文件后面有字符" | ",这个符号表示该文件是命名管道
2.通过函数使用

int mkfifo(const char* filename,mode_t mode)
//filename:管道文件名称
//mode:管道文件权限,成功返回0,失败返回-1

注意
当一个命名管道使用完毕之后并且不再被任何一个进程打开时,这个命名管道并没有被删除,而是继续存在于磁盘中,当需要打开这个命名管道时,就好像打开了磁盘中的文件一样,所以如果需要删除这个管道文件时,使用删除普通文件方法删除即可,删除的是磁盘上这个管道所对应的节点信息
匿名管道与命名管道的区别
匿名管道由pipe函数创建并打开,命名管道由mkfifo函数创建,打开使用open
所以当创建与打开指令完成之后,匿名管道与命名管道就没有语义上的区别了

共享内存

什么是共享内存?
和名字一样,共享内存指的就是两个进程访问同一块物理内存的通信方式。进程可以将共享的内存连接到各自的地址空间中,并且这块空间所有进程都可以访问到,那么当某个进程向共享内存中写入数据的话,那么这个改动完成之后,其它进程也可以看到。所以需要注意的是,共享内存并不提供同步机制,所以当一个进程在对共享内存进行写入操作完成之前,第二个进程也可以在此时进行读取,所以需要通过信号量等机制来实现共享内存的同步。并且在通信完成之后,所有进程都需要脱离共享内存,由一个进程完成释放这个共享内存的工作
共享内存特点
1.共享内存是最快的进程间通信方式,因为和其它的进程间通信比较的话,没有用户态和内核态之间的拷贝
2.生命周期随内核
共享内存通信原理
Linux下不同的进程有着自己独立的地址空间,通过各自的页表来将进程的虚拟地址空间映射到物理内存中,共享内存就是让通信的进程通过页表映射到物理内存中的这块共享内存实现进程间通信。
共享内存工作流程
1.创建共享内存:在物理内存中开辟一块空间

int shmget(key_t key,size_t size,int shmflg);
//key:内核中共享内存的标识符,通过这个标识符才能使多个进程打开同一个共享内存
//size:共享内存大小
//shmflg:参数IPC_CREAT,存在则打开,不存在创建
//返回值: 返回共享内存段的标识号,失败返回-1

2.进程将共享内存映射到自己的虚拟地址空间

void *shmat(int shmid,const void* shmaddr,int shmflg);
//shmid: 共享内存标识号
//shmaddr: 共享内存映射在虚拟地址空间中的首地址(一般置NULL)
//shmflg: 映射成功之后对共享内存可以进行的操作 SHM_RDONLY用于只读(前提是有读的权限),0-默认可读可写
//返回值:返回共享内存映射在虚拟地址空间中的首地址-通过这个首地址进行后序的内存操作 失败返回(void*)-1

3.通过内存操作对这块空间进行操作
4.使用完毕之后,解除虚拟地址空间与这块共享内存的映射关系
int shmdt(const void* shmaddr)
//shmaddr: 映射在虚拟地址空间中的首地址
//返回值: 成功返回0,失败返回-1
5.删除共享内存

shmctl(int shmid,int cmd,struct shmid_ds *buf);
//shmid:共享内存句柄
//cmd:对共享内存想要进行的操作 IPC_RMID-删除共享内存
//buf:用于获取/设置共享内存信息的结构,不使用则置NULL
//返回值:成功返回0;失败返回-1;

注意:
删除共享内存的时候,不会立即删除,为了不让这个共享内存继续与其它进程连接,则将其状态设置为被销毁状态,当这个共享内存的映射连接数为0的时候,就会删除这块共享内存

消息队列

什么是消息队列?
消息队列就是内核中的一个优先级队列,不同进程通过向同一队列中添加或删除节点实现进程间通信
消息队列特点
1.自带同步与互斥
2.生命周期随内核,因为进程间通信资源必须删除,否则不会自动删除(重启除外)
消息队列如何使用
1.创建消息队列

int msgget(key_t key,int msgflg);

2.向队列中添加/删除节点

int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg); msgtyp ---指定获取什么类型的数据与mtype对应
struct msgbuf{//因为系统页不知道你的数据有多长,因此这个结构体由用户自己定义
long mtype;  /* message type,must be > 0*/
char mtext[1]; /* message data */
};

3.删除消息队列

int msgctl(int msqid,int cmd,struct msqid_ds *buf);

信号量

什么是信号量?
信号量就是一个内核中的计数器和一个pcb等待队列,通过计数器对资源进行计数,进程在获取资源之前先通过这个计数判断能否访问资源,实现进程间的同步与互斥
信号量实现同步
通过计数器对资源进行计数,获取资源之前判断计数是否符合获取资源的条件,计数>0表示能够获取,计数<=0表示不能获取,通过等待接口使进程等待加入等待队列,等到有资源可以访问时唤醒这个进程
信号量实现互斥
通过计数器对资源进行计数,当计数器为1时,表示资源只有一份,保证了同一时间只能有一个进程访问资源

计数>0时可以访问,获取一个资源后计数-1
计数<=0时不能访问,计数-1,并且将pcb的状态置为可中断休眠状态,加入等待队列
当其它进程产生资源时,计数+1,此时若计数<0则什么也不做,若计数>0则从等待队列中唤醒一个进程去获取资源
如何理解信号量?
我们可以将信号量机制与生活中的例子关联起来,比如生活中的公交车座位,假设只有三个座位,开始时三个座位都是空的,此时如果同时来了五个人,那么只能有三个人坐在座位上,车辆管理员会让其它两个人只能站着等待有空座位出现,无论后面上来多少人也只能站着等待空座位,当有人离开时座位变成空座位哦,有几个空座位出现就让相应数目站着的人坐下,其它的人继续等待空座位的出现,依次类推。
在这个例子中,空座位就代表资源,人代表进程,车辆管理员的作用就是信号量的作用,不让多人共坐一位的情况发生

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值