Linux 创建子进程执行任务的实现方法

2019-01-16 22:31:41丽君

Linux 操作系统紧紧依赖进程创建来满足用户的需求。例如,只要用户输入一条命令,shell 进程就创建一个新进程,新进程运行 shell 的另一个拷贝并执行用户输入的命令。Linux 系统中通过 fork/vfork 系统调用来创建新进程。本文将介绍如何使用 fork/vfork 系统调用来创建新进程并使用 exec 族函数在新进程中执行任务。

fork 系统调用

要创建一个进程,最基本的系统调用是 fork:

# include <unistd.h> pid_t fork(void); pid_t vfork(void);

调用 fork 时,系统将创建一个与当前进程相同的新进程。通常将原有的进程称为父进程,把新创建的进程称为子进程。子进程是父进程的一个拷贝,子进程获得同父进程相同的数据,但是同父进程使用不同的数据段和堆栈段。子进程从父进程继承大多数的属性,但是也修改一些属性,下表对比了父子进程间的属性差异:

继承属性 差异
uid,gid,euid,egid 进程 ID
进程组 ID 父进程 ID
SESSION ID 子进程运行时间记录
所打开文件及文件的偏移量 父进程对文件的锁定
控制终端
设置用户 ID 和 设置组 ID 标记位
根目录与当前目录
文件默认创建的权限掩码
可访问的内存区段
环境变量及其它资源分配

下面是一个常见的演示 fork 工作原理的 demo(笔者的环境为 Ubuntu 16.04 desktop):

#include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(void) { pid_t pid; char *message; int n; pid = fork(); if(pid < 0) { perror("fork failed"); exit(1); } if(pid == 0) { printf("This is the child process. My PID is: %d. My PPID is: %d.n", getpid(), getppid()); } else { printf("This is the parent process. My PID is %d.n", getpid()); } return 0; }

把上面的代码保存到文件 forkdemo.c 文件中,并执行下面的命令编译:

$ gcc forkdemo.c -o forkdemo

然后运行编译出来的 forkdemo 程序:

$ ./forkdemo

fork 函数的特点是 "调用一次,返回两次":在父进程中调用一次,在父进程和子进程中各返回一次。在父进程中返回时的返回值为子进程的 PID,而在子进程中返回时的返回值为 0,并且返回后都将执行 fork 函数调用之后的语句。如果 fork 函数调用失败,则返回值为 -1。