在考研复习时候遇到的问题,很想写下来,虽然时间已经很紧张,但是在我们师生的问答互助之间,学术似乎更显神圣了,比起肮脏的考试制度来说……(请配合代码看)
问题表述:
在minix里面,使用如下命令会使系统在2个进程之间建立管道用来进行进程之间的通讯:
#cat file1 file2|sort
那么它的作用显而易见,列出file1和2的内容并排序放入另一文件。那么在内核当中是如何实现的呢?道理很简单,这条指令被shell接受以后会产生一个系统调用sys_call,名字是PIPE。调用的格式首先是使用库函数(minix的系统调用使用库函数)pipe(&fd[0]);其中fd[ ]这个数组的声明是这样子的:
int fd[2]
它是文件引用的数组,由于在2个进程当中,所以对文件使用2个引用定向到不同进程的输入输出就可以了。那么pipe建好了,其内容就是一个内存块m,m的2个域赋值给fd的2个cell,当然一读一写。好,然后我们开始fork系统调用,这次我们会得到2个进程,一对父子。下面我们假设从父亲发出信息,儿子取消息。我们会怎么做呢?
问题解决:
1.我们会关闭管道的读写,以备下面给父子分配读写引用
2.父子进程会由管道方向安排读写的放弃,例如,在这里,父亲放弃读引用STD_OUTPUT,儿子自然放弃
STD_INPUT,注意,这个时候有一个关键问题,也是我误解的问题,文件下面会使用dup函数重新连接2个
引用,机制是选择文件描述符的整数值最低的1个。那么文件描述符究竟是怎么分配的呢?经过林老师的指点
发现在每个进程有3个文件引用0-stdin,1-stdout,2-stderr,那么放弃1的父亲和放弃0的儿子就会分别
将新的文件引用dup到1和0上面
3.自然就是dup挂接引用了。注意dup里面使用了fcntl所以你将看到这个连接的方式就是从0开始找到最小的
空闲的描述连接他。至此pipe就建立了。特嫩鲍姆说他的minix的pipe最大时4096+3072,并且可以自行分配
空间大小,如果溢出,就会在loop当中死锁,这是显然的,呵呵。
#include STD_INPUT 0
#include STD_OUTPUT 1
pipeline(process1,porcess2)
char *process1,*process2;//旧的C标准参数声明吧~~~~~
{
int fd[2]; //存储读写的文件引用
pipe(&fd[0]);//create a pipe
if(fork()!=0){
//父进程的语句
close(fd[0]); //关闭管道读
close(STD_OUTPUT);
dup(fd[1]); //标准输出指向fd[1]
/*===============================================================================
/*这里是dup的原形*/
PUBLIC int dup(fd)
{
return(fcntl(fd,F_DUPFD,0));
}
==============================================================================*/
close(fd[1]); //不再需要描述符
execl(process1,process1,0);
}
else
{
//子进程的代码
close(fd[1]);
close(STD_INPUT);
dup(fd[0]);
close(fd[0]);
execl(process2,process2,0);
}
}
//===========================================================================================
copyright of all code used in this text belongs to Dr.Andrew S. Tanenbaum
thank you very much.
鸣谢:我的老师 林丰波先生,感谢他在百忙之中回答我的问题。
最后,祝愿包括自己在内天下考研同学成功~~~~~