如何在进入下一个周期之前等待 system() 完成

How to wait for system() completion before advancing into next cycle

我在 C 中使用 system("./foo 1 2 3") 来调用外部应用程序。我在 for 循环中使用它,我想在进入下一个循环迭代之前等待 foo 执行完成(每次执行需要 20/30 秒)。这是必须的。

返回的system()值只告诉我进程是否成功启动。那我该怎么做呢?

我已经调查了 fork()wait(),但没有做到我想要的。

编辑:这是我的 forkwait 代码:

for(i=0;i<64;i++){
        if((pid=fork()==-1)){
            perror("fork error");
            return -1;
        }
        else if(pid==0){
            status=system("./foo 1 2 3"); //THESE 1 2 3 PARAMETERS CHANGE WITHIN EACH ITERATION
        }
        else{                           /* start of parent process     */
            printf("Parent process started.n");
            if ((pid = wait(&status)) == -1)/* Wait for child process.      */
               printf("wait error");
            else {                       /* Check status.                */
               if (WIFSIGNALED(status) != 0)
                  printf("Child process ended because of signal %d.n",
                          WTERMSIG(status));
               else if (WIFEXITED(status) != 0)
                  printf("Child process ended normally; status = %d.n",
                          WEXITSTATUS(status));
               else
                  printf("Child process did not end normally.n");
            }
        }
 }

当我这样做时,PC 变得非常慢,以至于我需要手动重启。所以我猜这是在同时启动 64 个子进程,导致计算机变得非常慢。

在 POSIX 系统上,system 函数应该已经在等待命令完成。

http://pubs.opengroup.org/onlinepubs/009695399/functions/system.html

If command is not a null pointer, system() shall return the termination status of the command language interpreter in the format specified by waitpid(). The termination status shall be as defined for the sh utility; otherwise, the termination status is unspecified. If some error prevents the command language interpreter from executing after the child process is created, the return value from system() shall be as if the command language interpreter had terminated using exit(127) or _exit(127). If a child process cannot be created, or if the termination status for the command language interpreter cannot be obtained, system() shall return -1 and set errno to indicate the error.

需要注意的一件事是,如果您在命令中在后台启动程序(即,如果您正在执行 "./foo &")——显而易见的答案是不要那样做.

在您调用 fork 之后,child 会调用 system,这将启动 foo 运行的另一个 child。完成后,child 继续 for 循环的下一次迭代。因此,在第一个循环迭代之后,您有 2 个进程,然后是下一个之后的 4 个,依此类推。您正在以指数速度产生进程,这导致系统逐渐停止。

有几种方法可以解决这个问题:

  • 调用 system 后,您必须调用 exit,以便分叉 child 退出。
  • 使用 exec 而不是 system。这将在与 child 相同的进程中启动 foo。对 exec 的成功调用不会 return,但是如果它失败了,您仍然想要打印错误并在 exec.
  • 之后调用 exit
  • 根本不用 forkwait 而是循环调用 system,因为 system 不会 return 直到命令完成。

编辑:

这个循环表现出一些奇怪的行为。这是罪魁祸首:

if((pid=fork()==-1)){

你这里有些地方不对 parent。最里面的表达式是 pid=fork()==-1。因为 == 的优先级高于 =,所以它首先计算 fork()==-1。如果 fork 成功,则计算结果为 false,即 0。因此它计算 pid=0。所以在这个条件之后,parent 和 child 都有 pid==0.

应用上述其中一项更改后,将 parenthesis 放在正确的位置:

if((pid=fork())==-1){

一切都应该正常。

wait(2)

All of these system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal. In the case of a terminated child, performing a wait allows the system to release the resources associated with the child; if a wait is not performed, then the terminated child remains in a "zombie" state (see NOTES below).

If a child has already changed state, then these calls return immediately. Otherwise, they block until either a child changes state or a signal handler interrupts the call (assuming that system calls are not automatically restarted using the SA_RESTART flag of sigaction(2)). In the remainder of this page, a child whose state has changed and which has not yet been waited upon by one of these system calls is termed waitable.

我发现了问题所在。

我看到这里:https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file

为了将 stderr 保存到文件,我需要做 &>output.txt。 所以我在做 "./foo 1 2 3 &>output.txt" 但是 & 导致系统进程进入后台。

+1 到 @Random832 猜测它(即使我从来没有说过我正在使用 &> - 抱歉,伙计们,我的错)。

顺便说一句,如果你想将 stderr 导出到一个文件中,你可以使用 2>output.txt