我第一次看完这个例子,基本就懂了,但是dup2不是很懂。
下面挂两个链接,一个是这个例子的出处,一个dup2的讲解。
http://linux.chinaunix.net/techdoc/develop/2008/02/21/979889.shtml
但是这里还有点问题,就是管道的同步问题,ls,wc如果由于调度原因,先执行的父进程,也就是wc,wc没有输出,如何输出到标准输出?
对于写管道:
写入管道的数据按到达次序排列。如果管道满,则对管道的写被阻塞,直到管道的数据被读操作读取。对于写操作,如果一次write调用写的数据量小于
管道容量,则写必须一次完成,即如果管道所剩余的容量不够,write被阻塞直到管道的剩余容量可以一次写完为止。如果write调用写的数据量大于管道
容量,则写操作分多次完成。如果用fcntl设置管道写端口为非阻塞方式,则管道满不会阻塞写,而只是对写返回0。
对于读管道:
读操作按数据到达的顺序读取数据。已经被读取的数据在管道内不再存在,这意味着数据在管道中不能重复利用。如果管道为空,且管道的写端口是打开状
态,则读操作被阻塞直到有数据写入为止。一次read调用,如果管道中的数据量不够read指定的数量,则按实际的数量读取,并对read返回实际数量
值。如果读端口使用fcntl设置了非阻塞方式,则当管道为空时,read调用返回0。
#include
int fd[2];
void run_ls()
{
dup2(fd[1],1);
close(fd[0]);
close(fd[1]);
execve("/bin/ls",NULL,NULL);
}
void run_wc()
{
dup2(fd[0],0);
close(fd[0]);
close(fd[1]);
execve("/usr/bin/wc",NULL,NULL);
}
int main()
{
pipe(fd);
if(fork()==0)
run_ls();
else
run_wc();
return 0;
}
好,先面说说我的理解。pipe,建立一个管道,0是read,1是write。
子进程与行run_ls(父进程雷同,只说一个)。dup2的作用:
每个进程有自己的文件描述符表。
我们把fd看成一个结构体类型,就如上面图形中画的那样,我们不妨把之定义为:
struct fd_t {
int index;
filelistitem *ptr;
};
这
里
dup2(fd[1],1);的结果就是1这个fd原本指向的fileitem关闭了,他现在和fd[0]共享一个fileitem,fd[0]关闭后1
存在,所以这个fileitem不会关闭。1是原本是STDOUT,也就是标准输出关闭了,1指向了之前开辟的管道。
从上面的分析我们可以看
出,linux中创建进程是从父进程"fork"出来,然后再execve,而不是在创建时就指定它要运行的函数,完成独立地创建,这样天然的进程的继承
关系,为管道的实现提供了很大的方便,因为管道的实现利用了子进程继承父进程的文件描述符表这一特性。
阅读(3802) | 评论(0) | 转发(0) |