Linux 进程间通信

之前我们知道进程都有属于自己的虚拟地址空间,并且虚拟地址是根据页表的映射,在物理内存上找到一个属于自己的内存。所以进程之间都是互相独立的,各自完成自己的事情。那么进程之间就完全有联系了吗?答案是否定的。
那么进程间是如何进行联系的呢?这就需要我们学习进程间通信。

进程间通信

进程间通信的目的:
是为了让进程之间共用一块公共内存,共享其中的数据,从而进行数据的交换。
进程间通信的分类:
管道通信
匿名管道
命名管道
System V进程间通信
消息队列、共享内存、信号量(其中共享内存是速度最快的进程间通信)
POSIX进程间通信
消息队列、共享内存、信号量、互斥量、条件变量、读写锁

管道

管道是Unix最古老的通信方式,我们把一个进程链接到另一个进程的数据流叫做“管道”。简单的说管道就是一块内存,在内核中的缓冲区。
说一个很常见的例子:在我们Linux平台下一个命令|这就是一个管道。

匿名管道:

我们通过函数int pipe(int fd[2]);来创建匿名管道。
功能:创建一个无名管道
fd:文件描述符数组,fd[0]代表读端,fd[1]代表写端。
返回值:成功返回0,失败返回错误代码。

我们来看看管道的读写规则:
1.当没有数据可读时,也就是写端不写了,读端就会陷入阻塞,知道写端写数据。
2.当管道满的时候,也就是不去读一直写,那么管道的写端就会进行阻塞,知道读端读数据。

3.如果给读端设置非阻塞属性的话,若管道中没有数据,则返回-1。
4.如果给写端设置非阻塞属性的话,若管道中写满数据时,同样返回-1。

5.若读端关闭,写端往管道中去写时,就会导致操作系统给进程发送SIGPIPE信号,让当前进程退出。
6.若写端关闭,读端就会读完管道中的数据,之后返回,不会陷入阻塞,进程继续正常逻辑。

我们知道了管道的读写规则,下面来说说匿名管道的特点:
1.匿名管道是提供流式服务的。也就是说当我们往管道中写入数据的大小小于pipe_buf(管道大小)时,保证原子性。但是如果大于pipe_buf,则不保证原子性。
什么是原子性?
就是当前操作不可被打断,在这里意味着必须等一个进程写完另一个进程才能写。
2.匿名管道是半双工的。也就是读端只能读,写端只能写。若要用管道进行双向通信,只能用两个管道。
3.匿名管道的生命周期是跟随进程的。 因为管道是内核中的缓冲区,所以当进程退出,管道释放,管道的生命周期是跟随进程的。
4.匿名管道只能在具有亲缘关系的进程之间通信。 一般来说,一个管道由一个进程创建,当进程调用fork函数,之后,父子进程就可以通过管道通信了。
5.一般来说,内核会对匿名管道操作进行同步与互斥。 因为父子进程共享了匿名管道,所以管道又称为是临界资源

命名管道

如果我们不想像匿名管道那样只局限于相关进程间的通信,那么我们就可以用命名管道顾名思义,命名管道就是具有标识符让我们来找到它的管道,它是特殊文件类型。
创建一个命名管道文件的两种方式:
1.用命令去创建
mkfifo [命名管道文件名称]
2.使用函数去创建
int mkfifo(char* filename,mode_t mode);
创建一个命名管道后,我们可以通过系统调用open来打开命名管道,通过文件描述符来访问它,也就是说我们可以通过命名管道来访问内存中的缓冲区。

命名管道具有了文件标识符,因此可以进行不同进程间的通信。其他特性与匿名管道相同。

共享内存

那么什么是共享内存呢?
我们知道在虚拟地址空间中,堆栈之间有一个共享区,这个共享区就是在物理内存中找到一片内存区域(共享内存),将其通过页表映射到我们的共享区。此时不同的进程就可以在自己共享区上通过页表访问到这片共享内存,这时候就可以实现进程间通信了。

共享内存的特性
1.是最快的进程间通信。因为此种方式进行进程间通信,进程间数据传递不在经过内核。
2.不带有同步与互斥
3.写入数据是按覆盖的方式

使用共享内存流程:
1.我们用函数int shmget(key_t key, size_t size, int shmflg);来创建共享内存。
key共享内存标识符
size共享内存大小
shmflg打开共享内存方式,以及权限。
IPC_CREAT:如果共享内存不存在,创建。存在,返回共享内存即可。
IPC_CREAT|IPC_EXECL:如果共享内存不存在,创建。存在,报错。
加上权限:相当于文件的权限,8进制数字。

返回值:成功的话,返回共享内存的操作句柄。

2.用void *shmat(int shmid, const void *shmaddr, int shmflg);将进程附加到共享内存上。也就是说将共享内存段映射到进程的共享区
shmid:操作句柄。
shmaddr:映射到共享区的哪个位置,一般不用程序员去设置,给成NULL即可,由操作系统指定。
shmflg:0:可读可写。IPC_RDONLY:只读。
返回值:成功 :返回一个指针,映射到哪个地址上了。失败:-1。

3.用 int shmdt(const void *shmaddr);分离进程和共享内存。
shmaddr:shmat返回的地址。也就是当时映射到共享区的地址。
返回值:成功:0,失败:-1。

4.用int shmctl(int shmid, int cmd, struct shmid_ds *buf);销毁共享内存。
shmid:操作句柄。
cmd:使用什么操作。
IPC_STAT:获取当前共享内存状态,搭配shmid_ds一起使用。
IPC_RMID:删除共享内存,标记共享内存为删除状态。
buf:保存结构体中共享内存的一些信息。
返回值:失败-1。

如何查看共享内存:
ipcs -m
删除一个共享内存:
ipcrm -m [shmid]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值