文章目录
  1. fork系统调用
  2. exec系列系统调用
  3. 处理僵尸进程

fork系统调用

Linux下创建新进程的系统调用为fork。

1
2
3
4
5
6
/*
引用方式: #include <sys/types.h>
#include <unistd.h>
返回-1并设置errno: 失败
*/
pid_t fork();

该函数的每次调用都返回两次,在父进程中返回子进程的PID,则子进程中返回0。

fork函数复制当前进程的进程管理信息给子进程。子进程的进程管理信息大部分属性与原进程相同,如堆地址、栈地址、标志寄存器等;还要一些属性与父进程不同,如进程的PPID(设置为父进程的PID)、信号位图(所有位置0)。

此外,创建子进程后,父进程中打开的文件描述符默认在子进程中也是打开的,且文件描述符的引用计数加1。并且父进程的用户根目录、当前工作目录等变量的引用计数也会加1。

exec系列系统调用

exec系统调用将可执行文件替换当前进程映像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
引用方式: #include <unistd.h>
path: 指定可执行文件的完整路径
file: 接受文件名,此时程序会在环境变量PATH中寻找
arg: 接受可变参数, 将传递给新进程之main函数
argv: 接受参数数组, 将传递给新进程之main函数
envp: 设置新进程的环境变量; 若未设置envp参数, 则新进程将使用全局变量environ指定的环境变量
返回-1并设置errno: 失败
*/
int execl(const char * path, const char * arg, ...);

int execlp(const char * file, const char * arg, ...);

int execle(const char * path, const char * arg, ..., const char * envp[]);

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

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

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

若exec系列系统调用执行未出错,则原程序中exec调用之后的代码都不会执行!

exec系列系统调用在运行后不会关闭原进程打开的文件描述符,除非该文件描述符被设置了类似SOCK_CLOEXEC属性。

处理僵尸进程

对多进程程序而言,父进程需要跟踪子进程的退出状态;因此,子进程结束运行后,内核不会立即释放该进程的进程管理信息。

在子进程结束运行之后,父进程读取其退出状态之前,子进程处于僵尸状态。

此外,若父进程意外终止,也会使子进程进入僵尸态;此时子进程的PPID被设置为1(父进程为init进程)。之后,init进程接管该子进程并等待它结束。

僵尸进程占用内核资源;为此,Linux系统提供wait/waitpid函数来等待进程结束。

1
2
3
4
5
6
7
8
9
10
11
/*
引用方式: #include <sys/types.h>
#include <wait.h>
stat_loc: 存储子进程的退出状态信息
pid: 指定子进程的PID(pid=-1则waitpid等价于wait)
opt: 控制waitpid 函数的行为; 常见取值WNOHANG(此时waitpid调用是非阻塞的: 若pid指定的子进程还未结束, waitpid立即返回0)
返回结束的子进程的PID: 成功 || 返回-1并设置errno: 失败
*/
pid_t wait(int * stat_loc);

pid_t waitpid(pid_t pid, int * stat_loc, int opt);
  • wait函数将阻塞进程直到进程的某个子进程结束;
  • waitpid只等待pid结束;

同样地,只有在事件发生的情况下使用非阻塞调用才能提高程序的效率。而一个进程结束时,它将给它的父进程发送SIGCHLD信号来表明自身的结束。因此,父进程可捕获SIGCHLD信号,然后在信号处理函数中调用waitpid函数。

一种典型处理如下。

1
2
3
4
5
6
7
static void handle_child(int sig){
pid_t pid;
int stat;
while((pid=waitpid(-1, & stat, WNOHANG))>0){
// 对结束的子进程进行善后处理
}
}