execvp fork:等待标准输出

execvp fork : wait for stdout

我正在用 C 编写一个简单的 linux shell。

有时在使用 fork 然后执行 NON-BLOCKING 命令时 - 我的下一个 printf 消失了。我猜这是因为子进程正在写入标准输出。

如果我使用 waitpid 没有问题 - 因为我的下一个 printf 只会在子进程终止后打印。有时用户会想要执行非阻塞命令——然后我不会使用 waitpid——然后我的下一个 printf 就会消失。

如果我使用sleep(1)它也能解决问题。但我想知道是否有更优雅的方法来实现它。

int main( int argc, char *argv[], char *env[] )
{
   pid_t child_pid;
   int status;

   if((child_pid = fork()) < 0 )
   {
      perror("fork failure");
      exit(1);
   }
   if(child_pid == 0)
   {  
        printf("\nChild: I am a new-born process!\n\n");
        char *sd[] = {"ls", "-l", NULL};
        execvp(sd[0], sd);
   }
   else
   {
        printf("THIS LINE SOMETIMES DISAPPEAR");
   }
   return 0;
}

通常,当您期望 return 输出时,您会设置到 child 的显式 IO 管道。当您派生并执行 child 进程时,它将继承 parent 的文件描述符。因此,您想在执行命令之前通过调用 pipe(2). In the child, you redirect standard output and standard error to the write side of the pipe (using dup2(2)) 为 child 的输出创建一个单向管道。在 parent 中,您只需从管道的 读取端 读取直到 EOF,然后对输出做任何您想做的事情。然后你等待 child 退出。

这是一个没有任何错误处理的例子:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>


int
main(int argc, char *argv[])
{
    pid_t child;
    int p[2], to_parent, from_child;
    int child_status;
    char buffer[1024];
    ssize_t nread;

    /* create a unidirectional pipe
     * - child process will write to p[0]
     * - parent process will read from p[1]
     */
    pipe(p);
    from_child = p[0];
    to_parent = p[1];

    child = fork();
    if (child == 0) {
        /* child */
        /* close parent end of pipe */
        close(from_child);
        /* close unnecessary file descriptors */
        close(STDIN_FILENO);
        /* redirect standard output & error to pipe */
        dup2(STDOUT_FILENO, to_parent);
        dup2(STDERR_FILENO, to_parent);
        /* exec or die */
        execlp("ls", "ls", "-l", NULL);
        exit(EXIT_FAILURE);
    }

    /* parent */
    /* close child end of pipe */
    close(to_parent);

    /* read output from child until EOF */
    while ((nread=read(from_child, &buffer[0], sizeof(buffer))) > 0) {
        write(STDOUT_FILENO, &buffer[0], nread);
    }
    buffer[0] = '\n';
    write(STDOUT_FILENO, &buffer[0], 1);
    close(from_child);

    /* wait for child */
    wait(&child_status);                                                                            /*mindlessly copied from stack overflow*/
    if (WIFEXITED(child_status)) {
        printf("child %lu exited with code %d\n",
            (unsigned long)child, WEXITSTATUS(child_status));
    } else if (WIFSIGNALED(child_status)) {
        printf("child %lu terminated due to signal #%d%s\n",
            (unsigned long)child, WTERMSIG(child_status),
            WCOREDUMP(child_status) ? ", core dumped" : "");
    } else if (WIFSTOPPED(child_status)) {
        printf("child %lu stopped due to signal #%d\n",
            (unsigned long)child, WSTOPSIG(child_status));
    }

    return 0;
}

您必须小心关闭不必要的文件描述符。例如,让管道的 to_parent 端保持打开状态将导致 parent 的读取永远不会 return EOF。