LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2525|回复: 25

fork和资源的关系

[复制链接]
发表于 2005-10-4 16:50:32 | 显示全部楼层 |阅读模式
我写了一个程序,如下:
有一个缓冲区,在fork之后,子进程修改一个值,并打印该缓冲区的地址

main()
{
    char* array;
    array=(char*)malloc(sizeof(char)*5);
    strcpy(array,"abcd");
    pid_t pid;
    if((pid=fork())==0)
    {
        printf("pid:% d\n",pid);
        array[3]='o';
        printf("child array:%x,% s\n",array,array);
    }
    else
    {
        printf("pid:%d\n",pid);
        printf("father array:%x,%s\n",array,array);
    }
}

输出:
pid:0
child array:804a008,abco
pid:8745
father array:804a008,abcd


可以看出两个array的地址相同,这是否说明子进程和父进程共享同一个缓冲区呢?
但是如果是这样的话,上面表明子进程先运行,将abcd修改了为abco。
父进程后运行,但是缓冲区的内容却没有变,这好像有说明了子进程复制了父进程缓冲区,这到底是怎么回事呢?
谢谢。
发表于 2005-10-4 17:14:23 | 显示全部楼层
这些是虚拟地址。。。。相同没什么奇怪的。。
回复 支持 反对

使用道具 举报

发表于 2005-10-4 23:43:16 | 显示全部楼层
Post by marvel

可以看出两个array的地址相同,这是否说明子进程和父进程共享同一个缓冲区呢?

我个人是这样理解的:
对于fork来说,子进程和父进程之间是不共享的stack中的内存空间(auto类型) 。

地址相同是由于,fork调用的时候,子进程会复制一部分父进程的页表。

一旦子进程对stack中的内存写的时候,这时候才会改写页表,使之指向新的页帧(copy-on-write),所以地址是没有改变的,只是地址所对应的物理内存发生了改变。

不同的进程之间的地址空间是独立的,地址相同不代表什么!

希望说明白了!
回复 支持 反对

使用道具 举报

发表于 2005-10-5 00:02:05 | 显示全部楼层
不知道我说的对不对啊,子进程应该把father的所在内容都虚拟的都复制了一遍,包括marvel所说的内存地址!
但对于虚拟地址空间来说,它们不并指向同一个实际内存地址!
回复 支持 反对

使用道具 举报

发表于 2005-10-6 00:43:03 | 显示全部楼层
每个进程都有自己的独立的虚拟地址空间,和别的进程没有联系
地址相同不奇怪,而且是不可避免的
举个例子,每个进程都会把自己的可执行文件映射到从0x08048000开始的一段地址空间里

fork之后,子进程和父进程除了pid,ppid和一些琐碎的区别之外,完全一样
这个array变量的值自然不会有分别

因为父子进程的地址空间是独立的
你在子进程里做的修改当然也就不会在父进程中看到
回复 支持 反对

使用道具 举报

发表于 2005-10-6 00:46:21 | 显示全部楼层
Post by nuclearweapon

地址相同是由于,fork调用的时候,子进程会复制一部分父进程的页表。

复制页表不假,不过只有在解释物理地址为什么一样时才需要搬出这个论据
程序里打印出的地址只是虚拟地址
回复 支持 反对

使用道具 举报

发表于 2005-10-6 18:22:31 | 显示全部楼层
Post by zhllg
复制页表不假,不过只有在解释物理地址为什么一样时才需要搬出这个论据
程序里打印出的地址只是虚拟地址


一定要说的!! 这不是巧合和规定,在这里 虚地址相同,主要原因就是页表被复制。

因为,虚地址 对应的页表项,且
又因为,页表被复制。
所以,只有虚地址相同才能访问同样的页面。


嘿嘿!
回复 支持 反对

使用道具 举报

发表于 2005-10-7 00:36:47 | 显示全部楼层
难道以前没有COW的fork的时候
虚拟地址就会不同么?
不要误导别人

页表是做什么用的?cpu访问内存的时候,通过页表把虚拟地址转化成物理地址。(注意转化方向,虚拟->物理)这一过程是在硬件层次上发生的,对于用户空间应用程序来说是透明的。页表是硬件(CPU)需要的,用户空间应用程序不需要知道页表是什么值,甚至不需要知道页表的存在

这里虚拟地址肯定是相同的,不管fork的实现里是否复制页表
因为从语义上讲,fork之后父子进程资源基本一样,当然也包括虚拟地址空间(struct mm_struct)
do_fork()->copy_process()->copy_mm()

最后一点
这个问题根本用不到搬内核相关的东西出来,什么cow, 页表
解决楼主的疑问不需要这些深层的东西
不过既然楼上的兄弟提了,咱们就讨论清楚
回复 支持 反对

使用道具 举报

发表于 2005-10-7 10:25:39 | 显示全部楼层
Post by zhllg
难道以前没有COW的fork的时候
虚拟地址就会不同么?
不要误导别人

页表是做什么用的?cpu访问内存的时候,通过页表把虚拟地址转化成物理地址。(注意转化方向,虚拟->物理)这一过程是在硬件层次上发生的,对于用户空间应用程序来说是透明的。页表是硬件(CPU)需要的,用户空间应用程序不需要知道页表是什么值,甚至不需要知道页表的存在

这里虚拟地址肯定是相同的,不管是否复制页表
因为从语义上讲,fork之后父子进程资源基本一样,当然也包括虚拟地址空间(struct mm_struct)
do_fork()->copy_process()->copy_mm()

最后一点
这个问题根本用不到搬内核相关的东西出来,什么cow, 页表
解决楼主的疑问不需要这些深层的东西
不过既然楼上的兄弟提了,咱们就讨论清楚



楼上的兄弟,火气大了,我不是来这里显摆的!


你看下我的帖子,我强调的是“在这里”,也就是楼主所讨论的情况。
原因是:父进程的页表被子进程复制,
结果就是:父进程arry的虚地址地址,和子进程的虚地址是一致的。

也就是说,“在这里”虚地址相同是由于,复制页表了。

你要是还以为我在显摆的话,你自己问你一个问题。
要是这里虚地址不一样,结果如何??

至于是不是误道,我看只有您是这样理解的吧!
嘿嘿,楼上兄弟火气大!!!

再次强调,我不是在显摆什么。
回复 支持 反对

使用道具 举报

发表于 2005-10-7 11:13:49 | 显示全部楼层
这么说吧
一开始的fork的实现是不复制页表的
而是马上给子进程分配物理内存,页表自然不同
在那个时候的系统里,楼主的程序显示出的两个地址也是相同的


而实际上在楼主的程序里
打印的地址的时候页表已经不一样了
但打印的地址仍然是相同的

所以虚拟地址肯定一样,和如何fork如何实现(是否复制页表)_无关_
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表