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

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>


main(void)
{
  pid_t pid = fork();
   
  if( pid == 0 ) // this is the child process
  {
     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]);

     // 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)", 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, 底下有几个宏可判别结束情况:
//Linux <sys/wait.h>
#define WEXITSTATUS(s)  (((s) & 0xff00) >> 8)
#define WCOREDUMP(s)    ((s) & 0x80)
#define WTERMSIG(s)     ((s) & 0x7f)
#define WSTOPSIG(s)     WEXITSTATUS(s)

#define WIFEXITED(s)    (WTERMSIG(s) == 0)
#define WIFSTOPPED(s)   (WTERMSIG(s) == 0x7f)
#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;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值