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:非阻塞调用
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;
}
}