- /*************************************************************************
- > File Name: 2.c
- > Author: tp
- > Mail:
- > Created Time: Mon 07 May 2018 12:40:39 PM CST
- ************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- int set = 110;
- int main( void)
- {
- printf( "before fork\n");
- pid_t pid = fork( );
- if( pid < 0){ perror("fork"),exit( 1);}
- if( pid == 0)
- {
- ++set;
- printf( "son pid=%d, %d\n", getpid(), set);
- }
- else
- {
- sleep( 1);
- printf( "parent pid=%d , %d\n", getpid( ), set);
- }
- exit( 0);
- }
看一下结果:
不难注意到 "before fork" 这句话只是被打印了一次, 这个从上面的例子, 这不难理解; 与此同时
子进程中的
set 的值
被改变了
. 此时再进行一个重定向操作会发生什么
出现很神奇的现象! 这个时候打印了出了两次 "before fork", 不仅仅是如此, 上述针对父进程的标准输出执行重定向操作导致了让子进程也执行重定向的操作.
透过现象看本质, 来细细分析一下. 针对打印两次 "before fork", 首先, 先要知道标准 IO 库是带缓冲, 而像 printf 这种直接输出到标准输出时, 这个缓冲区是由换行符刷新的; 而当执行了重定向操作, 这里就是将标准输出重定向到文件, 文件就不会刷新缓冲区了, 好, 由于在 fork 之前调用了一次 printf, 但 fork 之后, 该行数据仍留着缓冲区, 然后父进程数据空间被复制到子进程中, 该缓冲去也被复制进去, 这样父子进程都各自带有该行内容的缓冲区了, 然后 exit 之前就又追加了一次 "before fork" 到缓冲区. 所以最后就打印了两次.
再一个就是, 在重定向父进程的标准输出时, 子进程标准输出也被重定向. 这就源于父子进程会共享所有的打开文件. 因为 fork 的特性就是将父进程所有打开文件描述符复制到子进程中. 当父进程的标准输出被重定向, 子进程本是写到标准输出的时候, 自然写到其它地方, 与此同时, 它还更新了与父进程共享的该文件的偏移量. 这里, 在父进程等待子进程执行时, 子进程将改为写到文件 show.out 中; 在子进程终止后, 父进程也写到 show.out 中, 同时其输出会追加在子进程所写数据之后.
在 fork 之后处理文件描述符一般又以下两种情况:
1. 父进程等待子进程完成. 此种情况, 父进程无需对其描述符作任何处理. 当子进程终止后, 它曾进行过读, 写操作的任一共享描述符的文件偏移已发生改变.
2. 父子进程各自执行不同的程序段. 这样 fork 之后, 父进程和子进程各自关闭它们不再使用的文件描述符, 这样就避免干扰对方使用的文件描述符了. 这类似于网络服务进程.
同时父子进程也是有区别的: 它们不仅仅是两个返回值不同; 它们各自的父进程也不同, 父进程的父进程是 ID 不变的; 还有子进程不继承父进程设置的文件锁, 子进程未处理的信号集会设置为空集等不同
来源: https://www.cnblogs.com/tp-16b/p/9005079.html