关于一段话的理解,请教
以下摘自<操作系统设计与实现>为什么我们不使用一个与文件描述符数组相平行的数组来给出文件当前位置呢?这个想法不可取,但是原因就更微妙了.问题来自Fork系统调用的语义 . 当生成一个进程时,父进程和子进程必需共享打开文件的指针.
为了更好地理解这个问题,我们考虑一个其输出重定位到某文件的shell脚本. 当该shell生成第一个子进程时,其标准输出文件的位置为0. 然后,子进程继承该位置,输出1k数据. 在子进程结束之后,共享文件位置应为1k.
假设shell读取更多的shell脚本,并且生成另一个子进程,第二个子进程必须从shell中继承1k的文件位置.这样,第二个子进程接着在第一个子进程的位置之后输出.如果shell不和子进程共享文件位置,那么第二个子进程可能重写第一个子进程的输出,而不是在第一个子进程的输出之后追加数据.
所以我们也不能把文件位置放在进程表中,它必需真正地实现共享.在minix中,解决这个问题的方法是引入一个新的共享表filp,其中包含了所有的文件位置.filp的使用,通过真正地共享文件位置,fork语义能正确地实现了,shell脚本也能正常工作了.
在第一段中提到的fork系统调用的语义是什么?
在倒数第二段中,"如果shell不和子进程共享文件位置,"不明白,为什么会出现这样的情况,在倒数第三段中子进程可以继承该位置,想问一下是否继承如何决定?
倒数第一段中说要实现真正的共享,这之前 为什么不叫真正的共享,区别在什么地方?
谢谢! 在第一段中提到的fork系统调用的语义是什么?
我想是指操作系统实现fork功能的规范,在这里是说,OS对fork系统调用的内核实现,在派生一个子进程的时候,父、子进程拥有同一个文件描述符结构(在内核里,是一个file结构,而不是整数),即由各自的task_struct结构的域files_struct里的fd数组里的一个元素指向的同一个file结构。
在倒数第二段中,"如果shell不和子进程共享文件位置,"不明白,为什么会出现这样的情况,在倒数第三段中子进程可以继承该位置,想问一下是否继承如何决定?
这两个问题,第一个只是一个假设,根据我们前面说的,事实上是共享的,只是告诉你不共享的坏处。后面一个问题,前面已经回答。
倒数第一段中说要实现真正的共享,这之前 为什么不叫真正的共享,区别在什么地方?
在你明白了前面说的问题,这就不是问题了。因为,前面我说的就是真正的共享,作者的意思是想渐进地引出为什么需要单独的file表来统一管理打开的文件。
而前面,files_struct的域fd就是存放的file地址指针,而file又由系统的I/O子系统负责管理。简而言之,进程控制结构只是维护的一组file结构的地址指针,当打开一个文件,I/O子系统创建一个file结构,当多次打开(比如fork),只是增加引用次数,当关闭一个文件(比如exit),也是减少file的引用次数,只有引用次数为0,才会释放file结构,而这些控制和进程没有直接关系,是I/O子系统负责的。
我不确定linux的文件的offset是在file结构的什么域表示,我想是kiobuf的offset。因为一个具体的文件只有一个file结构,因此,offset在系统的一个时刻也是有且唯一的值,这样就不会出现那个shell所说的冲掉的问题。 谢谢班主详尽的回复!
我还有三个问题:
1)
那么既然实际上不会出现shell不和子进程共享文件位置的情况,那么就不会出现不妥的地方呀!
2)如果将文件位置独立出来,就能解决shell不和子进程共享文件位置造成的不良影响吗?是如何解决的?
3)我的理解就是,那几段介绍的"将文件位置独立出来"的目的,就是用来解决"shell不和子进程共享文件位置"造成的不良影响的.
而且"不使用一个与文件描述符数组相平行的数组来给出文件当前位置"的原因就是可能产生"shell不和子进程共享文件位置"造成的不良影响.
不知道我的这种理解是否正确.
谢谢 我想很多操作系统的书都有这个方面的进程、文件描述符地址指针下标,文件描述符结构的关系图,看图理解会更清晰些。
我不是很明白你的问题,因为我看的都是文件描述实体独立的情况。换句话说,不管多少进程打开多少次一个文件,该文件只是维护一个file实体。如果该file实体不独立,这是什么意思?我想是说假设file属于task_struct的一个域(真实情况:task_struct只是间接的维护一个指向file结构的地址指针),必然会导致file的不一致现象(一个进程读了file,改变了file的成员,同时另一个进程的file还没改),而通过指针则不会出现萨。 谢谢 实际上不会出现shell不和子进程共享文件位置的情况,
no, it is possible that a parent process does not share any file struct with child process.
523 struct file {
524 struct list_head f_list;
525 struct dentry *f_dentry;
526 struct vfsmount *f_vfsmnt;
527 struct file_operations*f_op;
528 atomic_t f_count;
529 unsigned int f_flags;
530 mode_t f_mode;
531 loff_t f_pos;
532 unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
533 struct fown_struct f_owner;
534 unsigned int f_uid, f_gid;
535 int f_error;
536
537 unsigned long f_version;
538
539 /* needed for tty driver, and maybe others */
540 void *private_data;
541
542 /* preallocated helper kiobuf to speedup O_DIRECT */
543 struct kiobuf *f_iobuf;
544 long f_iobuf_lock;
545 };
that f_pos is the current offset. 喔,谢谢,linux代码还不熟。 :oops::wink: u already go so fast 可能我说的你已经知道了,重了就当我理解错了,呵呵
fork是个相当绕人的东西,至少我是这么觉得的
fork的意思是说进程分叉,这时内河只是把父进程的struct proc的内容拷贝给子进程,因此,fork调用之前的所有变量的值也会原封不动的烤给子进程,包括打开的文件描述信息,但这里要注意,fork之后,父进程和子进程的变量就无关了,各改个的。在文件描述信息里有一项是当前读写位移,如果这个也彼此无关的话就会出现覆盖的情况。
所以struct proc里的打开文件就使用指针或描述ID,这样被复制后他们还是在使用同一个文件描述信息,也就是同一个文件读写位移值。
btw,每次使用fork时我都觉得自己的思想也fork了,呵呵。 可能我说的你已经知道了,重了就当我理解错了,呵呵
fork是个相当绕人的东西,至少我是这么觉得的
fork的意思是说进程分叉,这时内河只是把父进程的struct proc的内容拷贝给子进程,因此,fork调用之前的所有变量的值也会原封不动的烤给子进程,包括打开的文件描述信息,但这里要注意,fork之后,父进程和子进程的变量就无关了,各改个的。在文件描述信息里有一项是当前读写位移,如果这个也彼此无关的话就会出现覆盖的情况。
所以struct proc里的打开文件就使用指针或描述ID,这样被复制后他们还是在使用同一个文件描述信息,也就是同一个文件读写位移值。
btw,每次使用fork时我都觉得自己的思想也fork了,呵呵。
should be correct. i forget os principle for a long time. kakuyou 说得太对了,就是这个意思,我终于明白了! cong!
页:
[1]