fork
对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一,因为它执行一次却返回两个值,以前"闻所未闻"。先看下面的程序:
int main() { int i; if (fork() == 0) { for (i = 1; i < 3; i++) printf("This is child process\n"); } else { for (i = 1; i < 3; i++) printf("This is parent process\n"); } } |
执行结果为:
This is child process This is child process This is parent process This is parent process |
fork在英文中是"分叉"的意思,一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就"分叉"了。当前进程为父进程,通过 fork()会产生一个子进程。对于父进程,fork函数返回子程序的进程号而对于子程序,fork函数则返回零,这就是一个函数返回两次的本质。
exec
在Linux中可使用exec函数族,包含多个函数(execl、execlp、execle、execv、execve和execvp),被用于启动一个指定路径和文件名的进程。exec函数族的特点体现在:某进程一旦调用了exec类函数,正在执行的程序就被干掉了,系统把代码段替换成新的程序(由 exec类函数执行)的代码,并且原有的数据段和堆栈段也被废弃,新的数据段与堆栈段被分配,但是进程号却被保留。也就是说,exec执行的结果为:系统认为正在执行的还是原先的进程,但是进程对应的程序被替换了。
fork函数可以创建一个子进程而当前进程不死,如果我们在fork的子进程中调用exec函数族就可以实现既让父进程的代码执行又启动一个新的指定进程,这很好。fork和exec的搭配巧妙地解决了程序启动另一程序的执行但自己仍继续运行的问题,请看下面的例子:
char command[MAX_CMD_LEN]; void main() { int rtn; /* 子进程的返回数值 */ while (1) { /* 从终端读取要执行的命令 */ printf(">"); fgets(command, MAX_CMD_LEN, stdin); command[strlen(command) - 1] = 0; if (fork() == 0) { /* 子进程执行此命令 */ execlp(command, command); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror(command); exit(errorno); } else { /* 父进程,等待子进程结束,并打印子进程的返回值 */ wait(&rtn); printf(" child process return %d\n", rtn); } } } |
这个函数实现了一个shell的功能,它读取用户输入的进程名和参数,并启动对应的进程。
|