linux的进程通信-管道

进程间通信
     每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到。
     在设计一个进程时,让进程感觉自己独占资源,一个进程占(可访问)的最大空间为2^32(32位下)(虚拟地址到物理地址的转换)
     例如对于父子进程来说,父子进程的数据会分离,一旦子进程要写入数据就会触发写时拷贝,子进程写的数据父进程不能看到
     进程间通信是本质是让不同的进程看到相同的系统资源,这个系统资源提供的不同,又分为很多通信方式
     所以进程要交换数据必须通过内核,在内核(内核-->操作系统 )中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再把数据从内核缓冲区把数据拷走,内核提供的这种机制称为进程间通信

一、管道
     管道是一种基本的IPC机制,由pipe函数创建
     #include<unistd.h>
     int pipe(int filedes[2]);
     调用pipe函数时在内核中开辟一块缓冲区用于通信,它有一个读端一个写端,然后通过filedes参数传出给用户程序的两个文件描述符。
     filedes[0]表示读端,filedes[1]表示写端,管道即一个打开的文件,故可以用文件描述符访问,向这个文件读写数据其实就是在读写缓冲区,pipe函数调用成功返回0,调用失败返回-1.

在这个进程基础上创建子进程,子进程将基础父进程的数据等,文件描述符表也将被继承

由于管道仅允许单向通信,所以父子进程需要指定谁是读端谁是写端,若是读端需要关闭写端,若是写端则需要关闭读端(保证单流向)
代码:


管道特性:
1.依赖文件系统,所以可以用文件的方式write、read
2.允许具有血缘关系的进程间通信
3.管道是一种单向通信,若想多向通信,则需要创建多个管道,
半双工:任意时刻仅有一方发送,不是单向通信
4.面向字节流(字节可以任意数量写,没有格式限制)
TCP也是面向字节流
5.管道就是文件,当进程退出时,进程资源也被回收进程在管道在,进程结束管道也结束。

四种特殊现象
1.写端关闭,而仍有读端读,则数据全部读取完后,read返回0;
2.写端不再写数据,读端把数据读完后阻塞,直到管道中有数据可读才读取数据
3.读端关闭,向管道写端会收到SIGPIPE信号,进程异常终止
4.读端未关闭,读端不读,写数据一端在管道写满时阻塞,直到有空位置才写入数据


以上为匿名管道(具有血缘关系的进程进行通信)

二、命名管道
     由于文件系统中的路径是全局的,各进程都可以访问,所以可以用文件系统中的路径来标示一个IPC通道
     命名管道也称FIFO文件,以文件名形式存在,行为和前的匿名管道类似,不过不限制血缘关系(父子、兄弟进程等)。
     创建命名管道的函数(二者均可):
#include <sys/types.h>  
#include <sys/stat.h>   
int mkfifo(const char *filename, mode_t mode);
int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0);   
其中,filename表示文件名,mode表示读写权限

创建两个进程,实现写端写入,读端读出数据
1.read.c

2.write.c

 那么一个管道的容量有多大?
     man 7 pipe

管道如何实现,操作系统是如何组织的?
     

管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数pipe_wrtie()。管道写函数通过将字节复制到 VFS 索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。

     当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:

 

       ·内存中有足够的空间可容纳所有要写入的数据;

       ·内存没有被读程序锁定。

 

如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。

     管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值