Linux 进程间通信1.0 — 管道:匿名管道 pipe

进程间通信

对于每一个进程来说这个进程看到属于它的一块内存资源,这块资源是它所独占的,这就导致进程之间的数据交换产生困难,为了解决进程间通信的问题。 因为交换数据必须通过内核,也就是说在内核中开辟一块缓冲区,进程1 把数据 写入 到内核缓冲区,进程 2 则从内核缓冲区中把数据 读走。 内核提供的这种机制称为进程间通信。

进程间通信的方式有:

  1. 匿名管道(pipe)和有名管道(FIFO)
  2. 信号(signal)
  3. 消息队列
  4. 共享内存
  5. 信号量
  6. 套接字(socket)

匿名管道 pipe

————————————————————————————————
管道的创建:
管道由 pipe 函数来创建,

SYNOPSIS
       #include 
       int pipe(int pipefd[2]);

pipe 函数会在 内核 中开辟一块缓冲区用于进程间通信,这块缓冲区称为 管道,有 一个读端(fd[0]),一个 写端(fd[1])。

pipe 函数接受一个参数——包含两个整数的数组,如果 pipe 调用成功,会给 pipefd[2] 赋值两个 文件描述符, fd[0] 为 读,fd[1] 为 写。

返回值
如果调用成功,则返回 0
否则 返回 -1

使用方式
先使用 pipe() 函数创立管道,确立 两个 文件描述符
1.父进程创建管道,得到两个文件描述符指向管道的两端

2.利用fork函数创建出子进程,则子进程也得到两个文件描述符指向同一管道

3.父进程关闭读端(pipe[0]),子进程关闭写端pipe[1],则此时父进程可以往管道中进行写操作,子进程可以从管道中读,从而实现了通过管道的进程间通信。

#include
#include

int main(){
// 声明:int pipe(int pipefd[2]);
        int fd[2];
        char buf[128];
        if(pipe(fd) < 0 ){
                printf("creat pipe failed \n");
                exit -1;
        }
//      printf("it is ok \n");
        int pid;
        pid = fork();     // fork()  创建 一个进程 
        if( pid < 0){
                printf("creat son failed\n");
        }
        else if(pid > 0){
                printf("into father \n");
                close(fd[0]);
                write(fd[1],"write from father",strlen("write from father"));
//              printf("write is over \n");     
        }
        else{
                printf("pid = %d,  into son\n",pid);
                close(fd[1]);
                read(fd[0],buf,128);
                printf("read from father : %s\n",buf);
        }
        return 0;
}

运行结果(看似出现了问题,其实只不过是父进程先结束,然后打印出命令行,而子进程又没有结束,然后打印子进程所产生这么一个事情神奇的现象;
Linux 进程间通信1.0 — 管道:匿名管道 pipe_第1张图片
之所以出现此现象,是因为,在 linux 系统中,是以 父进程 的结束 作为进入命令行的标识的,init 是一个后台进程,所以会出现,当父进程结束以后便 进入命令行的情况。

pipe的特点:

  1. 只能单向通信

  2. 只能血缘关系的进程进行通信

  3. 依赖于文件系统

  4. 生命周期随进程

  5. 面向字节流的服务

  6. 管道内部提供了同步机制

说明: 因为管道通信是单向的,在上面的例子中我们是通过子进程写父进程来读,如果想要同时父进程写而子进程来读,就需要再打开另外的管道;

管道的读写端通过打开的文件描述符来传递,因此要通信的两个进程必须从它们的公共祖先那里继承管道的件描述符。 上面的例子是父进程把文件描述符传给子进程之后父子进程之 间通信,也可以父进程fork两次,把文件描述符传给两个子进程,然后两个子进程之间通信, 总之 需要通过fork传递文件描述符使两个进程都能访问同一管道,它们才能通信。

四个特殊情况:

  1. 如果所有指向管道写端的文件描述符都关闭了,而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样

  2. 如果有指向管道写端的文件描述符没关闭,而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。

  3. 如果所有指向管道读端的文件描述符都关闭了,这时有进程指向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。

  4. 如果有指向管道读端的文件描述符没关闭,而持有管道写端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再write会阻塞,直到管道中有空位置了才写入数据并返回。

你可能感兴趣的:(Linux系统笔记,linux)