fork和vfork函数、wait和waitpid函数

每一个进程都有一个非负整型表示的唯一进程ID。因为进程ID标识符总是唯一的,常将其用作其他标识符的一部分以保证其唯一性。虽然是唯一的,但是进程ID可以重用。大多数UNIX系统实现延迟重用算法,使得赋予新建进程的ID不同于最近终止进程所使用的ID。这防止了将新进程误认为是使用同一ID的某个已终止的先前进程。

系统中有一些专用的进程,但具体细节因实现而异。ID为0的进程通常是调度进程,常常被称为交换进程(swapper)。该进程是内核的一部分,它并不执行任何磁盘上的程序,因此也被称为系统进程。进程ID 1通常是init进程,在自举过程结束时由内核调用。

除了进程ID,每个进程还有一些其他的标识符。如

#include <unistd.h>

pid_t getpid(void);   //返回值:调用进程的进程ID

pid_t getppid(void); //返回值:调用进程的父进程ID

uid_t getuid(void);  //返回值:调用进程的实际用户ID

uid_t geteuid(void); //返回值:调用进程的有效用户ID

gid_t getgid(void); //返回值:调用进程的实际组ID

gid_t getegid(void); //返回值:调用进程的有效组ID。

 

fork函数

一个现有进程可以调用fork函数创建一个新进程。

#include <unistd.h>

pid_t fork(void);

由fork创建的新进程被称为子进程(child process)。fork函数被调用一次,但返回两次。两次返回的唯一区别是子进程的返回值为0,而父进程的返回值为新子进程的进程ID。将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数使一个进程可以获得其所有子进程的进程ID。fork使子进程得到返回值为0的理由:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID(进程ID 0总是由内核交换进程使用,所以一个子进程的进程ID不可能为0)。

子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父、子进程并不共享这些存储空间部分。父、子进程共享正文段。

由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全复制。作为替代,使用了写时复制技术。这些区域由父、子进程共享,而且内核将它们的访问权限改变为只读的。一般来说,fork之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。

fork有下面两种用法:

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

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

 

vfork函数

vfork函数的调用序列和返回值与fork相同,但两者的语义不同。vfork用于创建一个新进程。而该新进程的目的是exec一个新程序。vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec,于是也就不会访问该地址空间。vfork和fork之间的另一个区别是:vfork保证子进程先执行,在它调用exec或exit之后父进程才可能被调度运行。

 

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。子进程终止是个异步事件,所以这种信号也是内核向父进程发的异步通知。调用wait或waitpid的进程可能发生的情况:

1.如果其所有子进程都还在运行,则堵塞。

2.如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

3.如果它没有任何一个子进程,则立即出错返回。

#include <sys/wait.h>

pid_t wait(int *statloc);

pid_t waitpid(pid_t pid,int *statloc,int options);

两个函数的返回值:若成功则返回进程的ID ,若出错则返回-1。

这两个函数的区别如下:

1.在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。

2.waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程。

这两个函数的参数statloc是一个整型指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。依据传统,这两个函数返回的整型状态字是有现实定义的。其中,某些位表示退出状态(正常返回),其他位则指示信号编号(异常返回),有一位指示是否产生一个core文件等。POSIX.1规定终止状态用定义在<sys/wait.h>中的各个宏查看。有四个互斥的宏可用来取得进程终止的原因,它们的名字都以WIF开始。

wait和waitpid返回的终止状态的宏

WIFEXITED(status),若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit、_exit和_Exit参数的低8位。

WIFSIGNALED(status),若为异常终止子进程返回的状态,则为真(接收到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status),取使子进程终止的信号编号。

WIFSTOPED(status),若为当前暂停子进程的返回状态,则为真。对于这种情况,可执行WSTOPSIG(status),取使子进程暂停的信号编号。

WIFCONTINUED(status),若在作业控制暂停后已经继续的子进程返回的状态,则为真。

 

如果一个进程有几个子进程,那么只要有一个子进程终止,wait就返回。如果要等待一个指定的进程终止,则使用waitpid。对于waitpid函数中pid参数的作用:

pid==-1;等待任一子进程。就这一方面而言,waitpid和wait等效。

pid>0;等待其进程ID 与pid相等的子进程

pid==0;等待其组ID 等于调用进程组ID的任一子进程。

pid<-1;等待其组ID等于pid绝对值的任一子进程。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值