fork函数的一些问题

1 #include <unistd.h>
2 
3 pid_t fork(void);


一个现有进程可以调用fork函数创建一个新进程。由fork函数创建的新进程称为子进程(child process)。fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值为0,而父进程的返回值则是新子进程的进程ID。

将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有的子进程ID。使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid获得其父进程ID。

子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。子进程获得父进程的数据空间、堆和栈的副本,注意,父子进程并不共享这写存储空间部分,而父子进程共享代码段。

由于在fork之后进程跟随exec,所以现在很多实现并不执行一个父进程数据段、栈和堆的完全复制。作为替代,使用写时复制(Copy-On-Write,COW)。这些区域由父子进程共享,而且内核将它们的访问权限改变为只读。如果父子进程中的任一个试图修改这些区域,则内核只为修改区域的那快内存制作一个副本,通常是虚拟存储器系统的一页。

在重定向父进程的标准输出时,子进程的标准输出也被重定向。实际上,fork的一个特性是父进程的所有打开文件描述符都被复制到子进程中。父子进程的每个相同的打开描述符共享一个文件表项。因此,这种共享文件的方式使父子进程对同一文件使用了一个文件偏移量。

父、子进程之间的区别是:

1、fork的返回值

2、进程ID不同

3、两个进程具有不同的父进程ID:子进程的父进程ID是创建它的进程的ID,而父进程的父进程ID则不变

4、子进程的tms_utime,tms_stime,tms_cutime以及tms_ustime均被设置为0

5、父进程设置的文件锁不会被子进程继承

6、子进程的未处理的闹钟被清除

7、子进程的未处理的信号集设置为空集

 

fork有两种用法:

1、一个父进程希望复制自己,使父子进程同时执行不同的代码段。比如在网络服务进程中,父进程等待客户端的服务请求,当请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。

2、一个进程要执行一个不同的程序。这种情况下,子进程从fork返回后立即调用exec。

 

 

下面看看vfork函数。

vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec或exit,相反,在子进程调用exec或exit之前,它在父进程的空间中运行。

另外,vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。所以如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

posted @ 2012-07-04 13:56  Cavia  阅读(1409)  评论(1编辑  收藏  举报