首页 > linux进程通信:pipe实现进程同步

linux进程通信:pipe实现进程同步

文章目录

        • 通过管道同步进程
        • 实现代码
        • 管道缓冲区
        • 设置缓冲区大小
        • 总结 :pipe的特点

通过管道同步进程

  • 管道自带同步互斥机制:
    • 管道的内核实现:fs/pipe.c ,主要通过内核的锁以及等待队列等机制实现
  • 管道的write操作会阻塞进程
    • 当内存缓冲区已满或被读进程锁定,会阻塞write操作
    • 当所有数据被写入管道时write操作才会结束
  • 管道的read操作会阻塞进程
    • 当读进程被阻塞时会形成等待队列,并让等待队列进入休眠
    • 当所有子进程关闭来管道的写入端的操作时会停止阻塞
    • 父进程的写入端操作关闭时,父进程的读操作会停止阻塞
    • 当所有当写端操作符都被关闭,且管道中当数据都被读出,对读端描述符调用read函数才会返回结束
    • 当所有当读取端和写入端都关闭后,管道才能被销毁

实现代码

#include 
#include 
#include 
#include 
#include 
#include #define handle_error(msg)
{perror(msg);exit(-1);}int main()
{ int pipe_fd[2];int buf;printf("parent process(%d) run ...
",getpid());if (pipe(pipe_fd) == -1)handle_error("pipe");for (int i = 0; i < 4; ++i) { int f;f = fork();if (f == -1)handle_error("fork");if(f == 0){ //这里子进程先休眠,然后离开之前关闭所有的读管道if (close(pipe_fd[0]) == -1)_exit(-1);sleep(i * i);printf("child process(%d) closing pipe
",getpid());if (close (pipe_fd[1]) == -1)_exit(-1);_exit(0);}}//在调用read系统调用之前一定要先关闭进程内所有的写管道,否则读会一直阻塞if (close(pipe_fd[1]) == -1)_exit(-1);// read系统调用正常读取文件会返回大于0都文件字节数。//但是当其读到EOF会返回0,标示读到结束标记//如果返回负数,则标示读取错误if (read(pipe_fd[0] ,&buf,1) != 0) perror("parent read can't get EOF");printf("parent process(%d) exited 
",getpid());return 0;
}

输出如下:

parent process(15454) run ...
child process(15455) closing pipe
child process(15456) closing pipe
child process(15457) closing pipe
child process(15458) closing pipe
parent process(15454) exited 

管道缓冲区

  • 管道对应缓冲区大小
    • PIPE_BUF的容量是有限制的,默认64K
    • 在不同的os下的PIPE_BUF大小设置不同:在limits.h头文件中定义
    • 当写入管道当数据超过PIPE_BUF的时候内核会分割不同的几块进行传输
    • 管道传输容量的缓冲区的容量上限设置不能超过1M
    • 查看打开的管道文件:ls /proc/$pid/fd

      可以在如上代码中的子进程处理代码中的close(pipe_fd[1])之前加入阻塞while(1);

      可以看到父进程有如下文件描述符打开,因为阻塞的子进程中写文件描述符未关闭,所以父进程的读文件描述符未关闭
    zhang@ubuntu:/proc/15521$ ls /proc/15691/fd/
    0  1  2  3
    
    子进程有如下文件描述符打开,因为子进程的写文件描述符关闭,所以4的描述符还存在
    zhanghuigui@ubuntu:/proc/15521$ ls /proc/15692/fd/
    0  1  2  4
    

设置缓冲区大小

  • 特权用户:可以修改缓冲上限
  • 设置缓冲区大小:fcntl(fd,F_SETPIPE_SZ,size)

总结 :pipe的特点

  • 无名管道是字节流
  • 可通过文件I/O接口读写,但是无法lseek修改文件指针的偏移地址
  • 单向阻塞通信:一端用于写入,一端用于读出。实现双向通信需要两个管道
  • 通信简单,性能单一,只能在亲缘进程间通信

更多相关:

  • 新建管道:   ​​​​​​​ng g pipe pipes/money或​​​​​​​ng g p pipes/money pipes/money.pipe.ts,同时在父级module.ts加入import { MoneyPipe } from './pipes/money.pipe'; @NgModule({  decla...

  • 几个术语 二义性:当我们往一个管道里面写端写数据的时候,比如写一个hello的时候,当我们写到he的时候,读端就已经开始读取数据了,所以这是不对的,这就是二义性临界资源:多个流可以访问的一个共同的存储资源临界区:访问临界资源的代码叫做临界区互斥:任一时候只能有一个进程利用临界资源访问临界区,并且是以原子性访问原子性:要么访问,要么没...

  • 在我们面试过程中,面试官经常会问到这么一个问题,那就是从在浏览器地址栏中输入URL到页面显示,浏览器到底发生了什么?这个问题看起来是老生常谈,但是这个问题回答的好坏,确实可以很好的反映出面试者知识的广度和深度。本文从浏览器角度来告诉你,URL后输入后按回车,浏览器内部究竟发生了什么,读完本文后,你将了解到:浏览器内有哪些进程,这些...

  • 进程与线程进程(process)就是任务,是计算机系统进行资源分配和调度的基本单位[1]。比如,打开一个word文件就是启动了一个word进程。线程(thread)是进程内的子任务。比如word中可以进行编辑、拼写检查和打印等子任务。我们目前的操作系统都是多任务的操作系统,多任务的实现方式[2]:多进程多线程多进程 + 多线程多进程:...

  • 运行cmd netstat -aon|findstr 80 然后 taskkill -f -pid 32428(这个就是pid进程编号) 回车   进程死翘翘了~ 去愉快玩耍吧~哦对了 别忘记一健三联关注我哟~...

  • 首要解决的问题是如何唯一标识一个进程,否则通信无从谈起!在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网...

  • 1.      SIGTERM “kill pid” 会发送SIGTERM到进程pid. This is the termination signal sent by killcommand by default. 2.      SIGINT 在终端中敲入interrupt key(DELETE或ctrl+c)会产生SIG...

  • 文章目录内核层实现结构通信原理特点使用函数声明使用实例单向通信双向通信编程注意事项管道中无数据时读操作会阻塞将管道的写端句柄关闭,不会影响读端数据读取管道中没有数据,写操作关闭则读操作会立即返回管道大小测试 64K管道发生写满阻塞,一旦有4k空间,写继续总结 内核层实现 结构 Linux操作系统中的无名管道结构如下图:...