linux IPC总结——管道

管道

管道是unix ipc的最古老形式,是一种在内存中的特殊文件,只能在具有公共祖先的进程之间使用(即父子进程,兄弟进程)。

管道由pipe函数创建

#include <unistd.h>

int pipe(int fd[2])

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

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

#include <unistd.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>

int main()
{
    int fd[2];
    char buf[80];
    pid_t pid;
    pipe(fd);
    pid = fork();
    if(pid>0)
    {//父进程
        printf("Father thread\n");
        char s[]="Hello\n";
        write(fd[1],s,sizeof(s));
        close(fd[0]);
        close(fd[1]);
    }
    else if(pid==0)
    {
        printf("Child Thread\n");
        read(fd[0],buf,sizeof(buf));
        printf("%s\n",buf);
        close(fd[0]);
        close(fd[1]);
    }
    waitpid(pid,NULL,0);//等待子进程结束
    return 0;
}

输出结果:

Father thread
Child Thread
Hello

当管道的一端关闭时:

  当读一个写端关闭的管道时,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;

  当写一个读端关闭的管道时,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则            是应用程序终止)。

从管道中读取数据:

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

向管道中写入数据:

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

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

FIFO

创建函数如下

 #include <sys/types.h>
 #include <sys/stat.h>

 int mkfifo(const char *pathname, mode_t mode);

第一个参数是一个普通的路径名,即为FIFO的名字。第二个参数设置权限,跟创建普通文件一样。

FIFO的读写也像普通文件一样,不过需要读写端都打开,具体规则如下:

当打开(open)时:

若没有设置O_NONBLOCK,只读open要阻塞到其它进程为写而打开FIFO。类似地,只写open要阻塞到其它进程为读而打开FIFO。

如果设置了O_NONBLOCK,则只读open立即返回,若没有其它进程为写而打开FIFO,则返回-1。

用FIFO模拟生产者消费者问题:

fifo2.cpp:

#include<iostream>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<limits.h>
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO "/tmp/myfifo"
#define BUF_SIZE PIPE_BUF
#define SEND_MAX (1024*1024*10)
using namespace std;

int main()
{
    int pid,fifo_fd;
    int send_num;
    char *buf[BUF_SIZE+1];
    if(-1 == access(FIFO,F_OK))
    {
        int res = mkfifo(FIFO,0777);
        if(res != 0)
        {
            fprintf(stderr,"can‘t create fifo in %s",FIFO);
            exit(EXIT_FAILURE);
        }
    }

    fifo_fd = open(FIFO,O_WRONLY);
    printf("process %d open fifo %d\r\n",getpid(),fifo_fd);
    if(fifo_fd == -1)
        exit(EXIT_FAILURE);
    int res;
    while(send_num<SEND_MAX)
    {
        res = write(fifo_fd,buf,BUF_SIZE);
        if(res == -1)
        {
            cout<<"write fifo error"<<endl;
            exit(EXIT_FAILURE);
        }
        send_num += res;
    }
    return 0;
}

fifo3.cpp

#include<iostream>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<limits.h>
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define FIFO "/tmp/myfifo"
#define BUF_SIZE PIPE_BUF
#define SEND_MAX (1024*1024*10)
using namespace std;

int main()
{
    int fifo_fd;
    int res;
    char buffer[BUF_SIZE+1];
    int read_num = 0;

    fifo_fd = open(FIFO,O_RDONLY);
    printf("process %d open FIFO %d\r\n",getpid(),fifo_fd);
    if(fifo_fd == -1)
        exit(EXIT_FAILURE);
    do{
        res = read(fifo_fd,buffer,BUF_SIZE);
        read_num += res;
    }while(res>0);
    close(fifo_fd);
    return 0;
}

结果如下:

可见读进程运行0.013s就读取了10m的数据,FIFO的效率还是很高的。

时间: 2024-12-28 08:02:59

linux IPC总结——管道的相关文章

Linux IPC之管道和FIFO

导言:管道是UNIX系统上最古老的IPC方法,管道提供了一种优雅的解决方案:给定两个运行不同程序的进程,在shell中如何让一个进程的输出作为另一个进程的输入?管道可以用来在相关(一个共同的祖先进程创建管道)进程之间传递数据.FIFO是管道概念的一个变体,它们之间的一个重要差别在于FIFO可以用于任意进程间的通信. 概述 每个shell用户都对在命令中使用管道比较熟悉,例如,统计一个目录中文件的数目: ls | wc -l 解释:为了执行上面的命令,shell创建了两个进程来分别执行ls和wc(

Linux编程 — IPC之管道

管道,一种古老的进程间通信形式.一个管道由一个进程创建,然后该进程调用fork,此后父.子进程就可以用管道通信了. 函数原型: #include <unistd.h> int pipe(int filedes[2]); // 成功返回0,出错返回-1 参数filedes返回两个文件描述符.filedes[0]用来输入,filedes[1]用来输出.注意,经过实验,这里的两个描述符并不对应标准输入和标准输出.下面是一个简单的测试例程: #include <stdio.h> #incl

Linux IPC实践(1) -- 概述

进程的同步与互斥 进程同步: 多个进程需要相互配合共同完成一项任务. 进程互斥: 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥;系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源, 而在进程中涉及到互斥资源的程序段叫临界区. Linux IPC发展 Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克

Linux IPC 共享内存用法

Linux IPC 常见的方式 写 Linux Server 端程序,必然会涉及到进程间通信 IPC. 通信必然伴随着同步机制,下面是一些常见的通信与同步机制: 进程间通信:匿名管道,命名管道,消息队列,共享内存,Domain Socket, 本机 TCP Socket,文件 进程间同步:信号,信号量 线程间同步:条件变量,互斥量,读写锁,自旋锁,Barrier. 对于大部分的业务场景,本机 TCP Socket 足以,现在Linux 也对本机 TCP Socket做了很好的优化.而且如果以后需

细说linux IPC(六):pipe和FIFO

在unix系统上最早的IPC形式为管道,管道的创建使用pipe函数: #include <unistd.h> int pipe(int pipefd[2]); 该函数创建一个单向的管道,返回两个描述符 pipefd[0],和pipefd[1],pipefd[0]用于读操作,pipefd[1]用于写操作.该函数一般应用在父子进程(有亲缘关系的进 程)之间的通信,先是一个进程创建管道,再fork出一个子进程,然后父子进程可以通过管道来实现通信.管道具有以下特点:管道是半双工的,数据只能向一个方向流

Linux IPC简单总结

###Linux IPC### --------------- ##消息传递## - 信号: 非亲缘,传递信息少,只能是控制信息而不是数据信息 - 管道: 要亲缘,无边界字节流,先进先出,消耗掉就没了,没有窥探功能MSG_PEEK - FIFO: 非亲缘,无边界字节流,先进先出,消耗掉就没了,没有窥探功能MSG_PEEK - Socket: 非亲缘,边界可有可无,效率较低 - Unix Socket: 非亲缘,边界可有可无,比Socket的效率高,比共享内存的效率低 - 消息队列:无亲缘,有边界

细说linux IPC(十一):各种IPC形式比较总结(完)

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 这个系列基本上到现在为止已经差不多把linux上的各种常用的IPC介绍完了,linux上面的IPC大多都是从UNIX上面继承而来. 最初Unix IPC包括:管道.FIFO.信号.System V IPC包括:System V消息队列.System V信号灯.System V共享内存区.由于Unix版本的多样性,电子电气工程协会(IEEE)开发

Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)

整理自网络 Unix IPC包括:管道(pipe).命名管道(FIFO)与信号(Signal) 管道(pipe) 管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信: 实现机制: 管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息.一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管

go语言快速入门 IPC之管道通信 8

熟悉Unix/C编程的应该对IPC也非常的熟悉,多进程之间的通信主要的手段有管道/信号量/共享内存/Socket等,而管道作为父子进程间进行少量数据传递的有效手段也得到了广泛的应用,在这篇文章中我们来看一下go语言中如何使用管道进行进程进行通信. 管道的使用 在linux下,管道被非常广泛地使用,一般在编程中我们实现了popen等的应用即可提供管道功能.而在命令行中使用地也非常多,|就是最为典型的管道的应用例子.shell会为|符号两侧的命令各创建一个脚本,将左侧的输出管道与右侧的输入管道进行连