【问题标题】:C - using exec() instead of system()C - 使用 exec() 而不是 system()
【发布时间】:2014-10-21 23:52:56
【问题描述】:

在以下代码中:

int main ( int argc, char *argv[] ) {
    int i, pid, status;

    for(i = 0; i < atoi(argv[1]); i++) {
        pid = fork();
        if(pid < 0) {
            printf("Error occured");
            exit(1);
        } else if (pid == 0) {
            status = system("./frun test.txt 1");
            if (status != 0)
                printf("ERROR, exited with %d\n", status);
            else
                printf("SUCCESS, exited with %d\n", status); // 0
            exit(0); 
        } else  {
            wait(NULL);
        }
    }
    return 0;
}

我正在使用 system() 来运行一个名为“frun”的程序 我的问题是 - 我将如何更改代码以使用 exec() 系列函数之一?

我的主要问题是我需要获取程序的退出代码,而我找不到使用 exec() 的方法,而 system() 只是返回退出状态。

【问题讨论】:

  • 这个问题似乎是题外话,因为它是关于说明标准手册已经完美记录的内容。
  • 您需要使用fork()exec*() 函数之一,以及wait()waitpid()
  • @YemSalat:这不仅仅是一个简单的改变。这些东西相当微妙,如果你想自己做这一切,你需要清楚 Posix 流程模型是如何工作的。乔纳森说正确的入口点,但这不是在公园里散步。预计会遇到僵尸,孤儿,蒙面人的信号停止,并被管道杀死很多。
  • @Trey,谢谢!已编辑。

标签: c exec fork system


【解决方案1】:

阅读等待和执行的手册页。

您等待从 fork 和 execing 创建的进程(回想一下 exec 替换了当前进程,因此您必须 fork 才能获得其退出代码)。这是来自等待的手册页:

无论其价值如何,都可以使用以下方式解释此信息 宏,在&lt;sys/wait.h&gt; 中定义并计算为整数表达式;这 stat_val 参数是stat_loc 指向的整数值。

  • WIFEXITED(stat_val)
    如果为子进程返回了状态,则评估为非零值 正常终止。
  • WEXITSTATUS(stat_val)
    如果WIFEXITED(stat_val) 的值非零,则此宏计算为 子进程传递给 _exit() 的状态参数的低 8 位 或exit(),或子进程从main() 返回的值。
  • WIFSIGNALED(stat_val)
    如果为子进程返回了状态,则评估为非零值 由于收到未捕获的信号而终止(请参阅&lt;signal.h&gt;)。
  • WTERMSIG(stat_val)
    如果WIFSIGNALED(stat_val) 的值不为零,则此宏计算为 导致子进程终止的信号的编号。
  • WIFSTOPPED(stat_val)
    如果为子进程返回了状态,则计算为非零值 目前已停止。
  • WSTOPSIG(stat_val)
    如果WIFSTOPPED(stat_val) 的值不为零,则此宏计算为 导致子进程停止的信号数。
  • WIFCONTINUED(stat_val)
    如果为子进程返回了状态,则评估为非零值 已从作业控制停止继续。

在您的情况下,您可能希望使用 WEXITSTATUS(stat_val) 来获取 8 位退出代码。

您调用waitpid(pid, stat_loc, options) 并传递从fork() 返回的pid、指向本地int(存储状态的位置)的指针,以及您的选项标志(或0)。您可以在pid != 0 的分支中执行此操作,因为这是原始过程。调用fork()(其中pid == 0)的原始进程将调用exec,因此被exec'd 命令替换。

这是一个可以适应你的代码的伪示例:

pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
        exec(/*look up the different functions in the exec family and how to use them*/);
}
else if (pid < 0)
{
        //uh oh
}
else
{
        waitpid(pid, &status, 0);
        printf("Exited with %d\n", WEXITSTATUS(status));
}

虽然你应该检查waitpid的结果。

【讨论】:

  • @YemSalat:不。如果成功,exec() 不会返回。如果exec() 返回,你就知道它失败了。如果exec() 返回,您的子进程(由fork() 创建)执行exec() 并退出(可能带有错误消息)。正如 Trey 所述,您的父进程执行 wait()waitpid()
  • exec 只有在失败时才返回,否则当前进程被替换,exec 不返回。这就是为什么你必须派生一个新进程并用 exec 替换它的原因。
  • @YemSalat:父进程等待子进程死亡(这是您正在从事的病态业务),wait*() 函数报告子进程的退出状态(如果孩子退出;如果孩子因收到信号而死亡,您将获得有关杀死它的信号的信息)。你需要找到并阅读基本的 Unix 手册;这是基本的 Unix(POSIX、Linux)的东西。
  • 在我提供的示例中,您将检查 WEXITSTATUS(status) == 0。在 *nix 中,他们使用的心态是,一个进程可以以一种方式成功并以多种方式失败,因此退出代码0 表示成功,!0 是某种特定的(希望是)失败。
  • 这就是 waitpid 中的第二个参数的用途。它将指向的 int 值设置为进程状态的某种表示形式,您可以将其传递给 WEXITSTATUS 等宏以从中提取特定值。您正在创建另一个由 exec 替换/使用的进程,并在父进程中等待由 fork 创建的进程的 pid(现在是您执行的任何进程)并获取状态。
猜你喜欢
  • 2013-01-27
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多