linux 中 execv, fork, wait 及 waitpid 的用法

来源:互联网 发布:费洛蒙 牌子 知乎 编辑:程序博客网 时间:2024/05/22 00:10
1. execv()
   1.1函数原型
      #include <unistd.h>
        int execv(const char *progname, char *const argv[]); 

   1.2 用法介绍

        execv会停止执行当前的进程,并且以progname应用进程替换被停止执行的进程,进程ID没有改变

        progname: 被执行的应用程序。

         argv: 传递给应用程序的参数列表, 注意这个数组的第一个参数应该是应用程序名字本身(即argv[0] = progname),并且最后一个参数应该为NULL,不能将多个参数合并为一个参数放入数组。

   1.3 返回值

       如果应用程序正常执行完毕,那么execv是永远不会返回的;当execv在调用进程中返回时,那么这个应用程序应该出错了(可能是程序本身没找到,权限不够等), 此时它的返回值应该是-1,具体的错误代码可以通过全局变量errno查看,还可以通过stderr得到具体的错误描述字符串。

#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <errno.h>#include <string.h>main(void){  pid_t pid = fork();     if( pid == 0 ) // this is the child process  {     const char *arg1 = "/bin/sh";     const char *arg2 = "-c";     const char *arg3 = "mkdir mydir";     const char *arg4 = NULL;     const char *arg[] = {arg1, arg2, arg3, arg4};     execv(arg[0], (char* const*)&arg[0]);     // the program should not reach here, or it means error occurs during execute the ls command.     printf("command ls is not found, error code: %d(%s)\n", errno, strerror(errno));  }}

2. wait(等待子进程中断或结束)
    2.1 函数原型
         #include<sys/types.h>
         #include<sys/wait.h>
         pid_t wait (int * status);

   2.2 函数说明:
       (1) wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用 wait()时子进程已经结束,则 wait()会立即返回子进程结束状态值。
       (2) 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。状态值status的具体含义请参考 waitpid()。
       (3) 如果执行成功则返回子进程PID,如果有错误发生则返回返回值-1,失败原因存于 errno 中。
       (4) 如果不需要status状态值,则参数 status 可以设成 NULL。

3. waitpid(等待子进程中断或结束)
     3.1 函数原型
          #include<sys/types.h>
          #include<sys/wait.h>
          pid_t waitpid(pid_t pid, int * status, int options);

    3.2 函数说明:
         (1) waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。
         (2) 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。
         (3) 如果执行成功则返回子进程PID,如果有错误发生则返回返回值-1,失败原因存于 errno 中。
         (4) 如果不在意结束状态值,则参数 status 可以设成 NULL。
         (5) 参数 pid 为欲等待的子进程识别码,其他数值意义如下:
              pid<-1  等待进程组识别码为 pid 绝对值的任何子进程。
              pid=-1  等待任何子进程,相当于 wait()。            
              pid=0   等待进程组识别码与目前进程相同的任何子进程。       
              pid>0   等待任何子进程识别码为 pid 的子进程。
         (6) 参数 option 可以为 0 或下面的 OR 组合:
              WNOHANG 如果没有任何已经结束的子进程则马上返回, 不予以等待。
              WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。

         (7) 子进程的结束状态返回后存于 status, 底下有几个宏可判别结束情况:
  1. //Linux <sys/wait.h>  
  2. #define WEXITSTATUS(s)  (((s) & 0xff00) >> 8)  
  3. #define WCOREDUMP(s)    ((s) & 0x80)  
  4. #define WTERMSIG(s)     ((s) & 0x7f)  
  5. #define WSTOPSIG(s)     WEXITSTATUS(s)  
  6.   
  7. #define WIFEXITED(s)    (WTERMSIG(s) == 0)  
  8. #define WIFSTOPPED(s)   (WTERMSIG(s) == 0x7f)  
  9. #define WIFSIGNALED(s)  (WTERMSIG((s)+1) >= 2) 

 a. WIFEXITED(status)       如果子进程正常结束则为true。exit(0), exit(-1), 都是正常结束。例如 exit(0), status = 0; exit(-1), status = 0xFF00; exit(-10), status = 0xF600
          b. WEXITSTATUS(status) 取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
          c. WIFSIGNALED(status)  如果子进程是因为信号而结束则此宏值为真。
          d. WTERMSIG(status)       取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
          e. WIFSTOPPED(status)   如果子进程处于暂停执行情况则此宏值为真。一般只有使用 WUNTRACED 时才会有此情况。
          f. WSTOPSIG(status)       取得引发子进程暂停的信号代码,一般会先用 WIFSTOPPED 来判断后才使用此宏。

     3.3 调用举例
int main() {      int cpid = fork();      if (cpid < 0) {          return -1;      } else if (cpid == 0) {          char *arg1 = "system/bin/sh";          char *arg2 = "-c";          char *arg3 = "mkdir mydir";          char *arg4 = NULL;          char *arg[] = {arg1, arg2, arg3, arg4};            execv(arg[0], &arg[0]);            printf("########## exec_command(): error code: %d(%s) ##########", errno, strerror(errno));            exit(-1);      } else {          int status = -1;          int count = 0;          while(1)          {              //int ret = waitpid(cpid, &status, 0); 如果子进程不结束会一直死等              int ret = waitpid(cpid, &status, WNOHANG);//WNOHANG 配合while 循环可以实现超时机制              if (ret) {                  if (WIFEXITED(status)) {                      //子进程正常结束: exit(任意值无论正负), execv()执行结束没有崩溃                      //1. execv()执行成功结束: status = 0                      //2. execv()执行结束,但可能没有执行成功,内部调用了exit(-1): status = 0xFF00                      //3. 子进程直接调用 exit(-1): status = 0xFF00                      //4. 子进程直接调用 exit(-10): status = 0xF600                      if (WEXITSTATUS(status) == 0xFF) {                          //TODO                      } else if (WEXITSTATUS(status) == 0xF6) {                          //TODO                      } else {                          //TODO                      }                  } else {                      //子进程非正常结束:子进程执行execv()发生崩溃,子进程是因为信号signal而结束                      //TODO                  }                  break;              }                if (++count >= 60) {                  //timeout = 60s                  break;              }              sleep(1);          }      }        return 0;  } 


0 0
原创粉丝点击