一个简单却不知道为什么出错的程序(附源码)?

nancygreen org 开发组长/高级工程师/技术专家  2006-02-20 11:55:34
#include<stdio.h>
main()
{
int p1,p2;
//printf("p1=%d,p2=%d\n",p1,p2); 带换行
//printf("p1=%d,p2=%d",p1,p2);  不带换行
while((p1=fork())==-1);
if(p1==0
putchar('b');
else{
while((p2=fork())==-1);
if(p2==0)
putchar('c');
else putchar('a');
}
}

在linux下编译,运行不带换行的printf,结果能正确的显示3次p1=...p2=....
而用带换行的那个printf,却只能显示1次p1=....p2=
这是怎么回事?
...全文
120 点赞 收藏 14
写回复
14 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
fierygnu 2006-02-21
我不用QQ、MSN这样的东西:(

指令流和内存是两回事。你找本操作系统或者计算机架构的书看看,或者仔细看看你上面给出的连接,或者看看fork的man page。
回复
nancygreen 2006-02-21
to fierygnu(va_list):
交个朋友吧,QQ:595602881
  在论坛里留言太累

  从哪里开始执行是不同的?为什么?它的本质应该是很简单的C语言程序,既然说是 父进程与子进程的代码是一样的 就是简单的代码共享或是copy一个幅本,谁跟你还区分从哪执行?,如果真做出这种区分也太难了,比方说如果在fork有定义变量,如果从fork执行的话,fork后面用到的变量是要重新定义的,但是你试试,不需要?证明不是从fork后面才开始执行!!!!
回复
fierygnu 2006-02-21
代码是一样没错,但从哪里开始执行是不同的。子进程从fork后的语句开始执行。
回复
nancygreen 2006-02-21
to fierygnu(va_list) :
你的观点不对吧,父进程与子进程的代码是一样的,具体解释参见    http://www.52wg.org/computer/chengxu/200511/computer_99939.html
回复
fierygnu 2006-02-21
但那个printf应该说是父子进程公共的代码,都会执行。
====
fork前没有子进程。子进程从fork点开始执行,前边的代码是不会执行的。fork不是exec或spawn。
回复
nancygreen 2006-02-21
to weirdy(远古传说) :
父进程和子进程的代码是一样的,只不过由fork()的返回值决定执行不同的部分,但那个printf应该说是父子进程公共的代码,都会执行。
  正如你所解释的:
1.
默认情况下标准输出是行缓冲的,就是说直到一行结束时缓冲区内容才全部显示到屏幕上。带换行的时候,printf("p1=%d,p2=%d\n",p1,p2); 执行完屏幕上就有输出,缓冲区也清空了,
  我认为三个进程应该显示3次p1=....p2=。。。后面跟abc(出现顺序是任意的),但它却只显示1次???!!!!

2. 
而printf("p1=%d,p2=%d",p1,p2);执行完屏幕上没有输出,缓冲区非空,存放着将要输出的内容,fork完后父子进程将有同样的输出缓冲区,当进程结束后会刷新,所以将有三p1=....p2=。。。
  如果是当进程结束时才被刷新,p1=...p2=...应该分别跟在顺序任意的abc后面,可执行结果是在它们前面。

你能进一步解释一下吗?谢谢!!!
回复
xenke 2006-02-21
默认情况下标准输出是行缓冲的,就是说直到一行结束时缓冲区内容才全部显示到屏幕上。带换行的时候,printf("p1=%d,p2=%d\n",p1,p2); 执行完屏幕上就有输出,缓冲区也清空了,所以三个进程显示1次p1=....p2=。。。后面跟abc(出现顺序是任意的),
printf("p1=%d,p2=%d",p1,p2);执行完屏幕上没有输出,缓冲区非空,存放着将要输出的内容,fork完后父子进程将有同样的输出缓冲区,当进程结束后会刷新,所以将有三个p1=....p2=。。。而且每个后面跟abc其中之一,顺序也是任意的。
回复
nancygreen 2006-02-21
哦,是哦,谢谢解惑!!!!
回复
fierygnu 2006-02-21
在fork前用scanf读入数据,看看子进程是否会再次等待输入,OK?
回复
nancygreen 2006-02-21
你能给我一段代码,让我从分析代码的角度去证实子进程确实从fork()后执行
当然除了有争议的printf之外,还有数据的+-*/ 因为也许你说的没错,是由于拷贝了内存的原因
好吗?我急需要一段代码的验证!!!
回复
fierygnu 2006-02-21
如果是那样的话,子进程不会执行前面的i++,也就是说子进程中i的值应该是1而实际上是2
====
那是因为拷贝了内存
回复
nancygreen 2006-02-21
man说的没错。但我认为应该这样去理解它的意思:它是说父进程里执行到fork()里,返回值是子进程的PID,而子进程执行到fork()函数时,它的返回值是0,然后程序继续执行。不是像你理解的子进程只执行fork()后的语句,如果是那样的话,子进程不会执行前面的i++,也就是说子进程中i的值应该是1而实际上是2,意味着子进程是执行了fork前面的i++.

回复
fierygnu 2006-02-21
//faint
看man了吗?
Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function.
回复
nancygreen 2006-02-21
大家看看这个源代码:
#include<stdio.h>
main()
{
int i=0,p,b=100;
i++;

while((p=fork())==-1) ;
if(p==0){
i++;
printf("\ni=%d, in child\n",i);
b=200;
}
else
printf("\ni=%d, in main\n",i);

printf("in both main and child: b=%d",b);
}

运行结果如下:

i=2, in child
in both main and child: b=200
i=1, in main
in both main and child: b=100

我认为父进程的执行是这样的:
#include<stdio.h>
main()
{
int i=0,p,b=100;
i++;

while((p=fork())==-1) ;
if(p==0){
i++;
printf("\ni=%d, in child\n",i);
b=200;
}//父进程里的fork()返回值为它创建的子进程的PID,所以p!=0,永远不会执行if中的语句   //而只能执行else里的
else
printf("\ni=%d, in main\n",i);

printf("in both main and child: b=%d",b);
}

子进程执行流程如下:
#include<stdio.h>
main()
{
int i=0,p,b=100;
i++;

while((p=fork())==-1) ;
if(p==0){
i++;
printf("\ni=%d, in child\n",i);
b=200;
}//因为子进程的fork()函数返回值是0,所以永远不会执行else里的语句
else
printf("\ni=%d, in main\n",i);

printf("in both main and child: b=%d",b);
}

在父子进程中,代码是共享的,但数据不是,数据只是一个拷贝,这个程序执行的结果就能说明这点。所以我还是觉得fierygnu(va_list)说子进程从fork后的语句开始执行是错的。
回复
相关推荐
发帖
Linux_Kernel
创建于2007-08-27

4152

社区成员

Linux/Unix社区 内核源代码研究区
申请成为版主
帖子事件
创建了帖子
2006-02-20 11:55
社区公告
暂无公告