Linux 进程间管道pipe通信

1. 函数说明

    pipe()会建立管道,并将文件描述词由参数filedes数组返回。对于调用fork 创建的子进程,父子进程之间通信常用pipe来实现,非常方便。

    #include<unistd.h>
    //参数
    //  filedes[0]为管道里的读取端
    //  filedes[1]则为管道的写入端
    //返回值
    //  若成功则返回零,否则返回-1,错误原因存于errno中
    //  errno代码:
    //  EMFILE 进程已用完文件描述词最大量
    //  ENFILE 系统已无文件描述词可用
    //  EFAULT 参数 filedes 数组地址不合法
    int pipe(int filedes[2]);
2. 应用举例1:阻塞调用

#include <unistd.h>
#include <stdio.h>

int main( void )
{
    int filedes[2];
    char buf[80];
    pid_t pid;
    
    pipe( filedes );
    pid=fork();        
    if (pid > 0) {
        char s[] = "Hello world , this is write by pipe.\n";
        write( filedes[1], s, sizeof(s) );
        close( filedes[0] );
        close( filedes[1] );

    }  else if(pid == 0) {
        read( filedes[0], buf, sizeof(buf) );
        printf( "%s\n", buf );
        close( filedes[0] );
        close( filedes[1] );
    }
    
    waitpid( pid, NULL, 0 );
    
    return 0;
}

调用fork后,子进程会复制父进程的进程信息,如文件描述符,这样fd[0], fd[1]在子进程中有同样的一个拷贝,他们的引用都为2,也就是两个进程在使用他们。当子进程调用close()来关闭fd[0],这是不成功的,因为这样只是将fd[0]的引用减少到1,fd[0]没有被系统回收;当父进程调用close(fd[0])时才会真正关闭。

3. 应用举例2:非阻塞调用

当管道中的数据被读取后,管道为空。一个随后的read()调用将默认的被阻塞,等待某些数据写入。若需要设置为非阻塞,则可做如下设置:
fcntl(filedes[0], F_SETFL, O_NONBLOCK);
fcntl(filedes[1], F_SETFL, O_NONBLOCK);
可以利用非阻塞调用实现timeout 机制:父进程每隔1秒循环读pipe,如果循环N次读不到子进程写过来的值,就直接timeout 返回。

#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>

int main()
{
    int result = -1;
    int filedes[2];
    int ret = pipe(filedes);
    if (ret != 0) {
        return -1;
    }
    ret = fcntl(filedes[0], F_SETFL, O_NONBLOCK);
    if (ret != 0) {
        return -1;
    }

    LOGD("fork new process...");
    pid_t cpid = fork();
    if (cpid < 0) {
        return -1;
    } else if (cpid == 0) {
        result = 200;
        write(filedes[1], &result, sizeof(result));
        close(filedes[0]);
        close(filedes[1]);

        sleep(20);//20 seconds
        //Note: 必须保证父进程先于子进程退出,这样子进程会被系统接管,当子进程执行完退出时,系统会自动回收。
        //如果父进程后退出,即使子进程执行完了,子进程的信息也会在系统中有残留,会变成僵尸进程。这个时候就需要
        //在父进程中调用waitpid(cpid, &status, 0),等待子进程执行完,这样子进程会被回收掉,不会有残留。
        //waitpid()的用法请参考 http://blog.csdn.net/wangbaochu/article/details/44087937
    } else {
        int count = 0;
        while(1) {
            read(filedes[0], &result, sizeof(result));
            LOGI("############## pipe read value= % d ##############", result);
            if (result == 200) {
                break;
            }

            if (++count >= 10) {//timeout = 10seconds
                LOGD("End waiting for son pid = %d, time out = 10 second”, cpid);
                int retval = kill(cpid, SIGKILL);
                if (retval) {
                    LOGD("Kill pid = %d Failed, result value = %d", cpid, retval);
                } else {
                    LOGD("Kill pid = %d Success", cpid);
                }
                break;
            }

            sleep(1);
        }

        close(filedes[0]);
        close(filedes[1]);
        return result;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值