日期:2014-05-16  浏览次数:20603 次

Unix高级环境编程的一条例题
既然是父子进程交替地对内存增加1,最后结果应该2000啊,为什么实际输出结果是1000?
如果说是fork后进程空间复制了一份,父子进程只是对各自的变量增自,那么update函数的返回值该如何解释呢?代码如下:

#include   "apue.h "   //包括TELL_WAIT()等进行同步的函数
#include   <fcntl.h>
#include   <sys/mman.h>

#define NLOOPS       1000
#define SIZE sizeof(long) /*   size   of   shared   memory   area   */

static   int
update(long   *ptr)
{
return((*ptr)++); /*   return   value   before   increment   */
}

int
main(void)
{
int fd,   i,   counter;
pid_t pid;
void *area;

if   ((fd   =   open( "/dev/zero ",   O_RDWR))   <   0)
err_sys( "open   error ");
if   ((area   =   mmap(0,   SIZE,   PROT_READ   |   PROT_WRITE,   MAP_SHARED,
    fd,   0))   ==   MAP_FAILED)
err_sys( "mmap   error ");
close(fd);/*   can   close   /dev/zero   now   that   it 's   mapped   */

TELL_WAIT();

if   ((pid   =   fork())   <   0)   {
err_sys( "fork   error ");
}   else   if   (pid   >   0)   { /*   parent   */
for   (i   =   0;   i   <   NLOOPS;   i   +=   2)   {
if   ((counter   =   update((long   *)area))   !=   i)
err_quit( "parent:   expected   %d,   got   %d ",   i,   counter);

TELL_CHILD(pid);
WAIT_CHILD();
}
}   else   { /*   child   */
for   (i   =   1;   i   <   NLOOPS   +   1;   i   +=   2)   {
WAIT_PARENT();

if   ((counter   =   update((long   *)area))   !=   i)
err_quit( "child:   expected   %d,   got   %d ",   i,   counter);

TELL_PARENT(getppid());
}
}

                printf( "value   in   process%d:   %ld\n ",   getpid(),   *(long*)(area));
               
exit(0);
}

------解决方案--------------------
既然是父子进程交替地对内存增加1,最后结果应该2000啊,为什么实际输出结果是1000?
如果说是fork后进程空间复制了一份,父子进程只是对各自的变量增自,那么update函数的返回值该如何解释呢?
====
1. for (i = 0; i < NLOOPS; i += 2)
注意是 i+=2 不是 i++ 所以只执行了500次
2. 既然是共享的,fork时,共享的部分不会复制。
------解决方案--------------------
在linux里,
fork()后的共享是采取了write on copy技术,即共享的数据只要在一方有写操作是才会真正的复制出来
这是为了提高效率而采取的一个措施.

------解决方案--------------------
mymtom(mymtom) 正解。我再补充一下:
这个例题是在15.9shared memory中的,用mmap() /dev/zero 来实现共享内存
1)fork()会复制父进程的data, stack, heap给子进程。而共享内存是在stack 和 heap 之间,不会被copy. 父子进程共享这片内存。交替+1,执行500次,所以是1000。
2)为什么用for (i = 0; i < NLOOPS; i += 2) , 用 i += 2? 因为父子进程都要判断 if ((counter = update((long *)area)) != i)。

------解决方案--------------------
共享, +2, 每进程500, 所以1000.
唉, 这问题过了, 结帖吧.