Linux启动新进程的几种方法及比较

2019-09-23 09:09:50王旭

输出结果为:

我们可以看到,之前在第二点中没有出现的ps Done是打印出来了,但是顺序却有点不对,这是因为,父进程先于子程序执行,所以先输出了Parent, ps Done,那有没有办法让它在子进程输出完之后再输出,当然有,就是用wait和waitpid函数。注意,一般情况下,父进程与子进程的生命周期是没有关系的,即便父进程退出了,子进程仍然可以正常运行。

2、等待一个进程

wait函数和waitpid函数的原型为:

#include <sys/types.h> 
#include <sys/wait.h> 
 
pid_t wait(int *stat_loc); 
pid_t waitpid(pid_t pid, int *stat_loc, int options); 

wait用于在父进程中调用,让父进程暂停执行等待子进程的结束,返回子进程的PID,如果stat_loc不是空指针,状态信息将被写入stat_loc指向的位置。

waitpid等待进程id为pid的子进程的结束(pid为-1,将返回任一子进程的信息),stat_loc参数的作用与wait函数相同,options用于改变waitpid的行为,其中有一个很重要的选项WNOHANG,它的作用是防止waippid调用者的执行挂起。如果子进程没有结束或意外终止,它返回0,否则返回子进程的pid。

改变后的程序保存为源文件new_ps_fork2.c,代码如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
  pid_t pid = fork(); 
  int stat = 0; 
  switch(pid) 
  { 
  case -1: 
    perror("fork failed"); 
    exit(1); 
    break; 
  case 0: 
    //这是在子进程中,调用execlp切换为ps进程 
    printf("n"); 
    execlp("ps", "ps", "au", 0); 
    break; 
  default: 
    //这是在父进程中,等待子进程结束并输出相关提示信息 
    pid = wait(&stat); 
    printf("Child has finished: PID = %dn", pid); 
    //检查子进程的退出状态 
    if(WIFEXITED(stat)) 
      printf("Child exited with code %dn", WEXITSTATUS(stat)); 
    else 
      printf("Child terminated abnormallyn"); 
    printf("Parent, ps Donen"); 
    break; 
  } 
  exit(0); 
} 

输出为:

可以看到这次的输出终于正常了,Parent的输出也在子进程的输出之后。

总结——三种启动新进程方法的比较

首先是最简单的system函数,它需要启动新的shell并在新的shell是执行子进程,所以对环境的依赖较大,而且效率也不高。同时system函数要等待子进程的返回才能执行下面的语句。

exec系统函数是用新的进程来替换原先的进程,效率较高,但是它不会返回到原先的进程,也就是说在exec函数后面的所以代码都不会被执行,除非exec调用失败。然而exec启动的新进程继承了原进程的许多特性,在原进程中已打开的文件描述符在新进程中仍将保持打开,但需要注意,任何在原进程中已打开的目录流都将在新进程中被关闭。