进程的通信是两个或多个进程实现数据的交互,让不同的进程看到同一份资源,而这份资源是由操作系统创建管理的。如果让其中一个进程来提供的话会破坏该进程的独立性,因为这个进程内部的数据可以被其他进程看到,那这个独立性就遭到了破坏。
管道
管道是一个内存级的文件,它并不存储在磁盘当中,而是只在内存存在,原本的文件缓冲区就成了存储数据的地方,读取该文件就是读取该文件的缓冲区。
管道文件是有固定大小的。
管道通信的原理
管道通信使用pipe系统调用以读写直接打开一个内存级文件,再创建一个子进程,继承指向该文件的文件描述符表,其中一个进程负责写,另一个进程负责读,负责写的进程关闭这个文件的读端口,负责读的关闭这个文件的写端口,这样就实现了进程单向通信。
但是管道通信只适用于有关系的进程,也就是继承下来了同一份字符描述符表,指向了该内存及文件的进程。
这个参数是一个输出型参数,需要的是一个数组,这个整数数组会把以读写方式打开的文件的两个文件描述符通过这个数组带出来。
返回值小于0说明创建失败
0是读下标
1是写下标
在进程通信时,进程之间会有协同的关系,如果一个文件正在写入,那么读端口就会等待写好,如果没有东西可以读取,那么就会等待写入端口写新的数据。
管道通信时会出现的四种情况
1.读写端正常,如果管道为空,那么读端就会阻塞。
2.读写端正常,如果管道为满,那么写端就会阻塞。
3.读端正常读,写端关闭,会读到0,表示读到了文件(pipe)结尾,且不会阻塞。
4.写端正常读,读端关闭,写端的进程会被操作系统发送信号杀掉。
命名管道
命令行创建
指令:
mkfifo 管道文件名
代码创建
成功返回0,失败返回-1.
第一个参数是文件名
第二个参数是文件权限
这个是在代码当中删除文件的函数,参数是文件路径名。
命名管道打开,在只有一方以写打开文件或以读打开文件时,会阻塞等待另一方打开文件才会继续执行。
共享内存
共享内存的生命周期是随内核的,如果用户不主动释放,或者对内核重启,共享内存会一直存在。
创建共享内存的大小推荐4096的整数倍,也就是一个内存块的大小。
一旦有了共享内存,挂接到了自己的内存空间中,你直接把他当成你的内存空间来用即可,不需要系统调用,直接拿着地址用就行
共享内存申请是一个系统调用,申请失败会返回-1,申请成功会返回一个共享内存的标识符。
第一个参数key是一个数字,有着唯一性,每一个共享内存有着唯一的一个key,如果这个key不存在,那么就可以新建一个共享内存,如果存在,那就能让调用的进程和其他进程共享这一块内存。
key的创建
第一个参数是一个字符串,第二个参数是一个数字,这个调用会用一套算法来将这两个参数计算返回一个key。想要获得同样的key,那两个参数也要一样。
第二个参数size是开辟的共享内存的大小。
第三个参数是要实现的功能选项。
IPC_CREAT 是一个宏定义,这个宏定义是一个整数,在二进制里面只有一个比特位为1,使用比特位来调用对应的功能。
IPC_CREAT 单独调用是,申请一块共享内存,若不存在,则创建,存在,则获取,返回。
IPC_CREAT|IPC_EXCL 是申请一块共享内存,不存在则创建,存在就报错返回。
同时也可以加入或权限进去
例:
IPC_CREAT|IPC_EXCL|0666
释放共享内存
ipcs -m
查看共享内存的key和shmid
key是key
shmid是shmid
owner是创建者
perms是权限
bytes是大小
nattch是挂接数
ipcrm -m shmid 删除对应的共享内存
共享内存挂接
第一个参数是shmid,第二个参数是想把这个共享内存放在虚拟地址共享区的什么位置,直接传NULL就可以,第三个参数是权限,如果想直接用之前申请共享内存时的权限,传输0就可以。
返回的就是该共享内存在虚拟地址的起始位置。
信号量
临界资源是将共享资源进行上锁之后的称呼,上锁后,一个进程访问这块临界资源时,其他的进程不能访问,管道文件就是临界资源。
临界资源分为两种,一种是只有一块整体的空间就是。这种临界资源的信号量是二元信号量,就是互斥,只存在0和1两种。
也可以将临界资源按照规定分块,多少块,信号量就是多少。
信号量本质是一个计数器,在使用临界资源时,需要先申请信号量,申请信号量实际上就是将信号量--,信号量为0时不能够再申请了,就算申请好不去使用,这块对应的临界资源也不能被其他申请。
申请好信号量之后才能去访问临界资源。
调用临界资源的那些代码被称为临界区域。