• [OS] 进程间通信--管道


    管道单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的首端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在数据写入管道前,进程将一直阻塞。同样,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直处于阻塞状态。
    管道主要用于不同进程间通信。

    下面介绍管道的使用方法:

    管道创建:

    1 #include <unistd.h>
    2 int pipe(int fd[2]);

    它接收一个参数,也就是包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描述符。创建一个管道之后,一般情况下进程将产生一个新的进程。
    系统调用:pipe();
    原型:int pipe(int fd[2]);
    返回值:成功返回0,失败返回-1。

    fd[1]写,fd[0]读。

    如下图所示,管道是在内核空间的内存中创建的。

    单个进程的管道几乎没有任何用处,通常,调用pipe的进程接着调用fork,这样就创建了父子进程间的管道。

     1 #include <unistd.h>
     2 #include<stdio.h>
     3 #include<sys/types.h>
     4 #include<sys/wait.h>
     5 
     6 int main()
     7 {
     8     int fd[2];
     9     char buf[80];
    10     pid_t pid;
    11     pipe(fd);
    12     pid = fork();
    13     if(pid>0)
    14     {//父进程
    15         printf("Father thread
    ");
    16         char s[]="Hello
    ";
    17         write(fd[1],s,sizeof(s));
    18         close(fd[0]);
    19         close(fd[1]);
    20     }
    21     else if(pid==0)
    22     {
    23         printf("Child Thread
    ");
    24         read(fd[0],buf,sizeof(buf));
    25         printf("%s
    ",buf);
    26         close(fd[0]);
    27         close(fd[1]);
    28     }
    29     waitpid(pid,NULL,0);//等待子进程结束
    30     return 0;
    31 }

    运行结果:

    Father thread
    Child Thread
    Hello
    

    当管道的一端关闭时:
    当读一个写端关闭的管道时,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;
    当写一个读端关闭的管道时,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

    从管道中读取数据:
    当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:PIPE_BUF在include/linux/limits.h中定义。

    向管道中写入数据:
    向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。

    管道因为没有名字所以只能用于具有亲缘关系的进程,而命名管道(FIFO)则克服了这个限制。

    命名管道和一般的管道基本相同,但也有一些显著的不同:
    ·命名管道是在文件系统中作为一个特殊的设备文件而存在的。
    ·不同祖先的进程之间可以通过管道共享数据。
    ·当共享管道的进程执行完所有的I/O操作以后,命名管道将继续保存在文件系统中以便以后使用。
    ·通过FIFO,不相关的进程也可以交换数据。

    下面是命名管道的使用方法:

    命名管道创建:

    1 #include <sys/types.h>
    2 #include<sys/stat.h>
    3 Int mkfifo(const char * pathname, mode_t mode);

    返回:成功返回0,出错返回-1。
    注:一旦已经用mkfifo创建一个FIFO,就可以用open打开。一般的文件I/O函数close, read , write等都可以用于FIFO。

  • 相关阅读:
    创建数据库的那些事
    同步、异步、阻塞、非阻塞我的理解
    Openfire MultiUserChat 多用户聊天 消息发送
    JAVA 随机字符串
    OF 同步异步问题的改进
    Openfire S2S 监听与消息处理
    MySQL FEDERATED 存储引擎
    一个S2S通信中的同步、异步问题的解决
    Openfire Monitoring/jinglenodes plugin error
    Java Cache System JCS(一) 使用方法
  • 原文地址:https://www.cnblogs.com/lca1826/p/6538221.html
Copyright © 2020-2023  润新知