读书人

求高手解释下这个只有3行的C程序多谢

发布时间: 2012-03-14 12:01:12 作者: rapoo

求高手解释下这个只有3行的C程序,谢谢了
int main()
{
printf("OK\n");
fork();
return 0;
}

这个程序已两种不同的方式运行,为什么输出不一样,求高手给我讲讲,谢谢!

方式1,直接运行: ./a.out 屏幕上输出1个OK
方式2,将输出重定向:./a.out >a.txt 文件a.txt里却有2个OK

创建子进程后,父子进程是继续执行fork调用之后的指令,就是说创建子进程后,父子直接return回去了,程序结束了,子进程并没有调用printf语句,那为什么会出现方式2的那种有2个OK?

求高手给我讲下,谢谢了!

[解决办法]
APUE讲了
standard output is line buffered if it's connected to a terminal device; otherwise, it's fully buffered.
[解决办法]

探讨
APUE讲了
standard output is line buffered if it's connected to a terminal device; otherwise, it's fully buffered.

[解决办法]
实例
程序8 - 1例示了f o r k函数。如果执行此程序则得到:
$ a . o u t
a write to stdout
before fork
pid = 430, glob = 7, var = 89 子 进 程 的变量值改变了
pid = 429, glob = 6, var = 88 父 进 程 的变量值没有改变
$ a.out > temp.out
$ cat temp.out
a write to stdout
before fork
pid = 432, glob = 7, var = 89
before fork
pid = 431, glob = 6, var = 88
一般来说,在f o r k之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的
调度算法。如果要求父、子进程之间相互同步,则要求某种形式的进程间通信。在程序8 - 1中,
父进程使自己睡眠2秒钟,以此使子进程先执行。但并不保证2秒钟已经足够,在8 . 8节说明竟
争条件时,还将谈及这一问题及其他类型的同步方法。在1 0 . 6节中,在f o r k之后将用信号使父、
1 4 2 U N I X环境高级编程
下载
子进程同步。
注意,程序8 - 1中f o r k与I / O函数之间的关系。回忆第3章中所述,w r i t e函数是不带缓存的。
因为在f o r k之前调用w r i t e,所以其数据写到标准输出一次。但是,标准I / O库是带缓存的。回
忆一下5 . 1 2节,如果标准输出连到终端设备,则它是行缓存的,否则它是全缓存的。当以交互
方式运行该程序时,只得到p r i n t f输出的行一次,其原因是标准输出缓存由新行符刷新。但是
当将标准输出重新定向到一个文件时,却得到p r i n t f输出行两次。其原因是,在f o r k之前调用了
p r i n t f一次,但当调用f o r k时,该行数据仍在缓存中,然后在父进程数据空间复制到子进程中时,
该缓存数据也被复制到子进程中。于是那时父、子进程各自有了带该行内容的缓存。在e x i t之
前的第二个p r i n t f将其数据添加到现存的缓存中。当每个进程终止时,其缓存中的内容被写到
相应文件中。
[解决办法]
就你代码而言在不是重定向下的情况下遍执行printf,由于遇到"\n"此时是stdout ,在默认下它是行缓冲的,遇到"\n"就立即把缓冲区内容写到屏幕,自然在执行printf后就之前立刻写掉了,自然fork后父子进程都不会再打印了。
而你重定向的时候缓冲类型就变成全缓冲了,执行printf后缓冲区没满或者没有执行fflush是不会写入文件的,自然fork后库函数中的缓冲区是有字符的,而此时是2个进程了!在进程退出时会执行exit操作,此操作2个目的,1.执行关闭所有输入输出流,在关闭之前执行fflush!,然后执行_exit程序终止,所以准确的说文件中的2个“OK\n”是程序退出时写上去的。
此外:
库函数缓冲区的三种类型:
全缓冲,行缓冲,无缓冲,默认情况下文件的缓冲是全缓冲的,stdout行缓冲的,而stderr是无缓冲的。
因此把您的程序“OK\n”改成“OK”
int main()
{
printf("OK");
fork();
return 0;
} 不管是用不用重定向 都会打出2个 OK

如果把上面程序中return 0改为 _exit(0)(注意是有下滑线的哦,return 0的外面实际上操作系统把return的值作为参数传给exit(),exit()中封装了_exit(),_exit()的作用是进入内核关闭该进程,因此我们下面的程序实际上是绕过了程序结束前的冲洗和关闭所有流的步骤,所以“OK”实际上是根本没有打出的,不管是用不用重定向 都一样“OK”是出不来 的)
int main()
{
printf("OK");
fork();
_exit(0);
}

读书人网 >C语言

热点推荐