进程访问机制,各个进程比较独立,不能访问对方的单元,但是进程不可能永远时对立的,必须涉及到信息的交互。
进程间通信传递两种信息,一种时标记、标志也就是状态(同步的状态信号量,异步的状态信号),另外一种是数据,即内容(传送的文件,磁盘、内存(有序的消息队列、共享内存,socket)、普通上锁文件、管道(有名管道、无名管道)、mmap。
管道的实现原理:
文件实现进程间的通信,普通文件可以同时被多个进程访问而无法相互感知,所以,不能使用普通文件来实现进程间通信(flock这个机制实际上是一个同步概念),因此出现了管道这个特殊的文件。由操作系统来维护的一段“内核内存空间”,类似与FIFO这种管道队列,因此称为管道。
(1)上层应用时,它就是文件,可以使用read/write/close等操作。
(2)它是特殊的文件,操作时不能进行lseek.
(3)管道是单向的。如果要实现双向,只能创建两个管道。
具体编程
(1)创建无名管道。pipe
int pipe(int pipefd[2]);
pipefd在调用者是一个数组,用来存放管道的两个返回文件描述符。
pipefd[0]用来读,pipefd[1]用来写。
(2)读写read/write函数。
read(fd[0],);
write(fd[1]);
(3)无名管道的限制
读写的限制
要进程读,就一定要有人写,要进行写,就一定有人要读。
(1)以阻塞方式读无名管道,如果当前没有一个进程(包括自己)与这个管道的写端关联,读操作立即返回。
如果有数据,且大于欲读出的数据量,读出试图读取的数据大小。
如果有数据,但是小于欲读出的数据量,读出所有管道数据。
如果没有数据,立即返回0.
(2)以阻塞方式读无名管道,有一个及以上进程(包括自己)与这个管道的写端关联,读操作做如下:
如果有数据,现有数据小于期望读取的值,读立即返回现有数据。
如果有数据,现有数据大于期望读取的值,读立即返回期望读写数据。
如果没有 数据,则阻塞,当有数据写入后,唤醒读操作。
(3)以阻塞方式写无名管道,如果有一个或者多个进程与这个管道的独端关联,如果当前管道已经满,则阻塞,当有进程读出数据,唤醒写操作。
(4)以阻塞方式写无名管道,如果没有进程与这个管道的读端关联,党有进程净产生SIFPIPE的信号,而这个信号的默认操作时种植当前进程,因此很多时候测试无效果,需要安装信号。
重定向及无名管道应用
<输入重定向,要求这个输入文件必须存在。
>输出重定向,如果文件不存在,创建,否则覆盖。
>>输出重定向,如果文件不存在,创建,否则追加。
2>
2>以上时对错误输出信息重定向到文件。
实现ps aux | grep test 或者 who | sort
(1)两个通信进程,ps aux 用execX函数来执行,grep init 是另一个进程,用execX来执行。为了方便,由一个父亲进程来创建这两个进程的通信。
(2)管道。这个管道要被两个进程都访问,父子进程。
(3)实现重定向。文件描述符复制。在ps aux中输出重定向,即将fd[1]复制为1,即以后写入到1中的数据全部写入到fd[1]中。默认情况下,一个进程的0,1,22三个文件描述符是默认打开的。因此,怎末来复制实现。
int dup(int oldfd);
复制oldfd为当前进程中最小未使用的文件描述符。
close(1);
dup(fd[1]);
如果0是默认打开的,dup函数返回1,以后写入到1的内容也就写入到fd[1]中。
int dup2(int oldfd,int newfd);
更方便是使用dup2,将oldfd复制为newfd,如果newfd关联打开的一个文件,则关闭这个文件。再复制。
dup2(fd[1],1)
能够保证fd[1]为后续输入出重定向的文件。
文件描述符的复制与新开文件是有本质区别的。复制文件描述时,两个文件描述共享文件表项,即共享读写文件。
新打开一个文件,其实时额外的申请文件表项,两者互不影响。
无名的管道,通信方向要了解创建的管道对应的文件描述符,因此,多用于父子进程或者亲缘关系之间,因为可以方便的实现文件描述符传递,
在重定向中还有流的重定向。popen/pclose.