1.fork函数
#inlcude <unistd.h>
pid_t fork(void);
由fork创建的新进程被称为子进程(child process)。fork函数被调用一次,返回两次。两次返回的唯一区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。子进程是父进程的副本。父、子进程并不共享存储空间部分(数据空间,堆和栈)。父、子进程共享正文段。
一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的。解决的方法是使用信号是父、子进程同步。
2. 文件共享
在重定向父进程的标准输出时,子进程的标准输出也被重定向。实际上,fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中。
在fork之后处理文件描述符有两种常见的情况:
1) 父进程等待子进程完成。在这种情况下,父进程无需对其描述符做任何处理。
2) 父、子进程各自执行不太的程序段。这种情况下,在fork之后,父子进程各自关闭不需要使用的文件描述符,这样不会干扰对方使用的文件描述符。
3. 父、子进程区别
1) fork的返回值
2) 进程ID
3) 子进程的tms_utime, tms_stime, tms_cutime以及tms_ustime均被设置为0
4) 父进程设置的文件锁不会被子进程继承
5) 子进程的未处理的闹钟(alarm)被清除
6) 子进程的未处理信号集设置为空集
4. fork失败的原因
1) 系统已经有太多的进程
2) 该实际用户ID的进程总数超过了系统限制
5. fork的应用
1) 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。例如,网络服务中,父进程等待客户端服务的请求。
2) 一个进程要执行一个不同的程序。在这种情况下,子进程从fork返回后立即调用exec函数。
6. fork函数与vfork函数区别
1) vfork函数也创建一个子进程,但是并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是不会存放该地址空间。相反,在进程调用exec(或exit)前,它在父进程的空间中运行。
2) vfork保证子进程先运行,在进程调用exec(或exit)之后进程才可能被调度运行。
7. fork与I/O函数见的交互关系
先看一个小程序:
编译该程序,执行它,如下:
[wzhwho@local~]$ ./a.out
The secret that cannot say
before fork
pid = 1039, global = 7, val = 100
pid =1038, global = 6, val = 99
[wzhwho@local~]$ ./a.out > tmp
[wzhwho@local~]$ cat tmp
The secret that cannot say
before fork
pid = 1039, global = 7, val = 100
before fork
pid =1038, global = 6, val = 99
write函数是不带缓冲的,因为fork之前调用write,所以其数据写到标准输出上只有一次。但是,标准I/O函数是带缓冲的。如果标准输出到终端时,它是行缓冲的,否则它是全缓冲的。当以交互方式运行该程序时,只得到该printf输出的行一次,原因是标准输出缓冲区由换行符来冲洗。当将标准输入重定向到一个文件时,去得到了printf输出行两次,是因为在fork前调用了printf一次,但当调用fork时,该行数据仍在缓冲区中,然后将父进程数据空间复制到了子进程时,该缓冲区也被复制到子进程中。当每个进程终止时,最终会冲洗其缓冲区中的副本。