免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1977 | 回复: 5
打印 上一主题 下一主题

请教fork下的文件I/O问题及内核驱动程序 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-01-08 15:40 |只看该作者 |倒序浏览
小弟最近正在学习Unix/Linux下的编程知识,以《Unix/Linux编程实践教程》为参考,在学习了fork函数后,做书后习题时遇到了下面的问题。

    请先看两段短代码:
(1)
#include <stdio.h>
#include <string.h>

int main()
{
        int fd;
        int pid;
        char msg1[] = "Test 1 2 3 ..";
        char msg2[] = "Hello ,hello\n";

        if((fd = creat("testfile",0644)) == -1)
        {
                return 0;
        }        
        if(write(fd,msg1,strlen(msg1)) == -1)
        {
                return 0;
        }
        //begin to fork
        if((pid = fork()) == -1)
        {
                return 0;
        }
        if(write(fd,msg2,strlen(msg2)) == -1)
        {
                return 0;        
        }
        close(fd);
        return 1;
}
(2)
#include <stdio.h>
#include <string.h>

int main()
{
        FILE *fp;
        int pid;
        char msg1[] = "Test 1 2 3 ..\n";
        char msg2[] = "Hello ,hello\n";

        if((fp = fopen("testfile2","w")) == NULL)
        {
                return 0;
        }
        fprintf(fp,"%d:%s",getpid(),msg1);
        //begin to fork
        if((pid = fork()) == -1)
        {
                return 0;
        }
        fprintf(fp,"%d:%s",getpid(),msg2);
        fclose(fp);
        return 1;

}

以上代码运行结果分别如下:
调用了write的程序结果是1个Test...2个Hello....
调用了fprintf/fwrite的程序结果是2个Test...2个Hello....

当然,一般情况下对fork的使用不这么用,但是,通过这两个例子,想请教以下几个问题:
1。当第一个例子fork出和原进程一样的子进程时,两个进程的具有相同的fd,而这两个进程同时也拥有一样的保存文件当前位置的指针,执行程序前我以为两个进程都向同一位置写入数据会导致一条的写入丢失,而事实上2条写入都生效。请问,这个保存文件位置的指针为两个进程所共享吗?它位于哪里呢?是存放于内核中吗?一个进程的写入会导致另一个进程看到文件指针的变化情况?
2。第二个例子出现了2个Test...2个Hello....,这个好像是缓冲的原因?fprintf/fwrite最终会调用write系统调用向磁盘写入数据?自己感觉fprintf/fwrite的实现中有缓冲机制,不知是否正确。如果有的话,这个缓冲区是依属于进程,所以fork后每个进程都有个自己的fprintf缓冲?
3。学习中发现write操作也并不是直接写入硬盘,也是写入一个所谓的内核缓冲区。当达到一定程度,该缓冲区数据被真正写入硬盘等外设。这个write写入的缓冲区与fprintf/fwrite的缓冲区(如果有)都位于系统的什么地方,有什么联系呢?
4。内核中有负责文件读写的驱动程序,而用户空间可能有很多进程涉及文件读写的操作,可能是都操作一个文件,也可能操作各自不同的文件。驱动程序与用户空间中的进程是什么关系呢?是一个用户空间的进程对应一个内核驱动程序的进程的副本,还是不管用户空间有多少涉及文件I/O的进程,而内核中只有一个运行着的驱动程序?如果这样,该驱动程序中是否存有保存各个进程的文件I/O信息的数据结构呢?这个问题始终不太明白。

谢谢大家的解答。

论坛徽章:
0
2 [报告]
发表于 2008-01-08 18:15 |只看该作者
1。当第一个例子fork出和原进程一样的子进程时,两个进程的具有相同的fd,而这两个进程同时也拥有一样的保存文件当前位置的指针,执行程序前我以为两个进程都向同一位置写入数据会导致一条的写入丢失,而事实上2条写入都生效。请问,这个保存文件位置的指针为两个进程所共享吗?它位于哪里呢?是存放于内核中吗?一个进程的写入会导致另一个进程看到文件指针的变化情况?

当前文件偏移量是保存在进程的文件表项中的,可能多个文件描述符指向同一文件表项,也可能分别指向不同的文件表项。fork之后的父子进程对于每一个打开文件描述符都共享同一个文件表项,dup也是如此,你的第一个例子的测试结果就是因为这个原因。如果是两个完全独立的进程打开同一个文件,就不是这样了。
多个进程打开同一文件,可能产生预料不到的结果,一般开发不这么做。

2。第二个例子出现了2个Test...2个Hello....,这个好像是缓冲的原因?fprintf/fwrite最终会调用write系统调用向磁盘写入数据?自己感觉fprintf/fwrite的实现中有缓冲机制,不知是否正确。如果有的话,这个缓冲区是依属于进程,所以fork后每个进程都有个自己的fprintf缓冲?

fwrite这些函数其实都是对write等系统调用的包装,增加了缓冲而已,其实你也可以自己实现这些函数。每个进程都有自己的缓冲区,fork之后这个缓冲区也被复制,因此得到了第二个例子的结果。

3。学习中发现write操作也并不是直接写入硬盘,也是写入一个所谓的内核缓冲区。当达到一定程度,该缓冲区数据被真正写入硬盘等外设。这个write写入的缓冲区与fprintf/fwrite的缓冲区(如果有)都位于系统的什么地方,有什么联系呢?

write确实也有缓冲区,这个在操作系统内核里;而fwrite的缓冲区在各自进程空间中。

4。内核中有负责文件读写的驱动程序,而用户空间可能有很多进程涉及文件读写的操作,可能是都操作一个文件,也可能操作各自不同的文件。驱动程序与用户空间中的进程是什么关系呢?是一个用户空间的进程对应一个内核驱动程序的进程的副本,还是不管用户空间有多少涉及文件I/O的进程,而内核中只有一个运行着的驱动程序?如果这样,该驱动程序中是否存有保存各个进程的文件I/O信息的数据结构呢?这个问题始终不太明白。

驱动程序和进程应该是没有直接联系的,它们之间是通过操作系统关联的,这也是操作系统存在的一个意义,不需要用户进程直接面向硬件。
用户进程中也不应该有驱动程序的副本,可以说操作系统就是一个服务端,提供接口(系统调用)给用户进程使用,用户进程只要正确使用系统调用即可。
因此,驱动程序中也不会保存各个进程有关文件I/O的信息。
没有接触过驱动程序,不敢保证第4个问题是完全正确的。

论坛徽章:
0
3 [报告]
发表于 2008-01-08 22:56 |只看该作者

回复 #2 Sorehead 的帖子

讲得太好了!

论坛徽章:
0
4 [报告]
发表于 2008-01-09 00:48 |只看该作者

回复 #2 Sorehead 的帖子

牛!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

论坛徽章:
0
5 [报告]
发表于 2008-01-09 09:29 |只看该作者
真的谢谢Sorehead ,这里给我家的感觉。。。呵呵

论坛徽章:
0
6 [报告]
发表于 2008-01-09 10:53 |只看该作者
再问驱动程序:
其实第四个问题是在学习设置驱动程序的属性时产生的。通过学习,了解到虽然Linux/Unix把外设(如终端,打印机等)都当成文件来对待,但由于这些设备本身性质的差异,决定了虽有统一的外貌(文件形式),但各自有各自的属性。这个可以通过fcntl、tcget/setattr等系统调用在各自的驱动程序中进行设置。而这些函数的其中一个参数都是fd。
1.是不是对于同一个驱动程序,不同的fd可以设置各自的属性?例如:对于磁盘驱动程序而言,设置O_SYNC后是不论何种程序的write调用都不再缓冲,还是关闭缓冲只对某一个fd起作用?
2.驱动程序是如何做到这一点的呢?
3.linux下终端的概念是什么呢?终端是一种外设(如键盘+显示器)?但键盘和显示器只有一个,而终端可以开多个。对于某一终端的属性设置显然不能影响其他终端,是否终端驱动在里面做了工作而将各个终端区别对待?使各个终端都有各自的属性?简单的tcgetattr(0,&inof),就可以取得某一终端的信息?每个进程都有0,1,2三个fd值,这些fd值与某一终端如何关联?
4.在linux下,fd值与标准库的File *fp有什么区别和联系?fd究竟是什么?
呵呵,问题问得比较散乱,这些知识可以在哪本书中找到详细的答案呢?谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP