fork、execl , waitpid实现父子进程管道间通讯

来源:互联网 发布:淘宝c店未授权怎么卖 编辑:程序博客网 时间:2024/06/06 03:41

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连贯用起来,实现了阻塞父进程等待子进程完成方可继续的功能。

0 0