fork和exec函数

fork函数调用一次,返回2次

它在调用进程中返回一次,返回值是新派生进程的进程ID号

在子进程又返回一次,返回值是0

因此,返回值本身告诉当前进程的子进程还是父进程

 

fork在子进程返回0而在父进程返回进程ID的原因在于:

任何子进程只有一个父进程,而子进程总是可以通过调用getppid取得父进程的进程ID

相反,父进程可以有许多子进程,而且无法获取各个子进程的ID

如果父进程想要跟踪所有子进程的进程ID,那么它必须记录每次调用fork的返回值

 

父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享

我们可以看到网络服务器利用了这个特性:

父进程调用accept之后调用fork

所接受的已连接套接字随后就在父进程和子进程之间共享

通常情况下,子进程接着读写这个已连接套接字,父进程则关闭这个已连接套接字

 

fork有2种经典用法:

1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作

这是网络服务器的典型用法

2)一个进程想要执行另一个程序

既然创建新进程的唯一办法就是调用fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本调用exec把自身替换成新的程序

这是诸如shelll之类程序的典型用法

存放在硬盘上的可执行程序文件能被unix执行的唯一方法是:

由一个现有进程调用6个exec函数中的一个,exec把当前进程映像替换成新的程序文件,而且该新程序通常从mian函数开始执行

进程ID并不改变

我们称调用exec的进程为调用进程,称执行的程序为新程序

 

这6个exec函数之间的区别在于:

1)待执行的程序文件是由文件名还是由路径名指定

2)新程序的参数是一一列出还是由一个指针数组来引用

3)把调用进程的环境传递给新程序还是给新程序制定新的环境

 

int execl( const char * pathname, const char* arg0 , ...);

int execv( const char* pathname, char* const argv[]);

int execle(const char* pathname, const char* arg0);

int execve(const char* pathname,char* const argv[],char* const envp[]);

int execlp(const char* filename, const char *arg0, ...);

int execvp(const char* filename,char* const argv[]);

 

这些函数只在出错时才返回到调用者

否则,控制将被传递给新程序的起始点,通常就是main函数

 

一般来说,只有execve是内核中的系统调用,其他5个都是调用execve

 

posted @ 2016-04-03 17:15  ailx10  阅读(403)  评论(0编辑  收藏  举报