1、创建管道
#include <unistd.h>
int pipe(int fd[2])
2、管道的读写规则
管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。
记住:fd[0] 是管道读 fd[1]是管道写,管道一旦创建这两个就是固定的,不可以改变。
3、管道和父子进程通讯的机制
调用fork后,子进程会复制父进程的进程信息,如文件描述符,这样fd[0], fd[1]在子进程中有同样的一个拷贝,他们的引用都为2,也就是两个进程在使用他们。而实际上父进程只使用fd[1],子进程只使用fd[0],这样如果父进程不想使用fd[1]了,调用close()来关闭fd[1],这是不成功的,因为这样只是将fd[1]的引用减少到1,fd[1]没有被系统回收,仍然在子进程中有效,所以必须父进程close(fd[0]);子进程close(fd[1])。
4、execl函数
int execl(const char *path, const char *arg, ...);
execl()其中后缀"l"代表list也就是参数列表的意思,第一参数path字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]... 最后一个参数须用空指针NULL作结束。
成功则不返回值, 失败返回-1, 失败原因存于errno中,可通过perror()打印
5、waitpid函数
#include<sys/types.h>#include<sys/wait.h>定义函数 pid_t waitpid(pid_t pid,int * status,int options);waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用 wait()时子进程已经结束,则 wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数 status 可以设成 NULL。如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回返回值-1。失败原因存于 errno 中。
4.example
父进程读,子进程写
父进程:
int main()
{
int pipe_fd[2];
pid_t pid;
int iRet = 0;
char acFd1[10];
char acFd2[10];
char r_buf[100];
memset(r_buf,0,sizeof(r_buf));
/*创建管道*/
if(pipe(pipe_fd)<0)
{
printf("pipe create error ");
return -1;
}
snprintf(acFd1, sizeof(acFd1), "%d", pipe_fd[0]);
snprintf(acFd2, sizeof(acFd2), "%d", pipe_fd[1]);
/*子进程*/
if((pid=fork())==0)
{
printf(" ");
iRet = execl("/home/zhanghl/test", "test", acFd1, acFd2, NULL);
if(iRet < 0)
{
printf("%d\n", error);
}
}
/*父进程*/
else if(pid>0)
{
if(waitpid(pid, NULL, 0) < 0)
{
printf("%d\n", error);
}
/*关掉写*/
close(fd[1]);
iRet = read(fd[0], r_buf, sizeof(r_buf));
if(iRet > 0)
{
printf("r_buf = %s\n", r_buf);
}
close(fd[0]);
}
}
子进程
int main(int argc, char argv[])
{
int fd0 = 0;
int fd1 = 0;
char w_buf[20] = {0};
snprintf(w_buf, sizeof(w_buf), "%s", "adafafaf");
fd0 = atoi(argv[1]);
fd1 = atoi(argv[2]);
close(fd0);
write(fd1, w_buf, sizeof(w_buf));
close(fd1);
exit(0);
return 0;
}
父进程fork子进程后,通过调用execl函数传递管道fd给子进程,子进程读取入参写数据到管道中,父进程等待子进程的结束,子进程结束后,读取管道的数据并打印出来。
一个简单的例子把fork、execl、waitpid、pipe连贯用起来,实现了阻塞父进程等待子进程完成方可继续的功能。