【问题标题】:Forking and Waiting in linux (C++).linux (C++) 中的分叉和等待。
【发布时间】:2017-05-23 13:20:38
【问题描述】:

我想 fork 一个进程,然后在父进程中执行以下操作:

  1. 等到它自然终止或父设置的超时期限到期(类似于 Windows 中的 waitforsingalobject),之后我将使用 kill(pid) 终止进程;

  2. 获取子进程的退出码(假设自然退出)

  3. 我需要从父进程访问子进程的 std::cout。

我尝试使用 waitpid(),但是虽然这允许我访问返回代码,但我无法使用此函数实现超时。

我还查看了以下解决方案 (https://www.linuxprogrammingblog.com/code-examples/signal-waiting-sigtimedwait),它允许我实现超时,但似乎没有办法获取返回码。

我猜我的问题归结为,在 linux 中实现这一目标的正确方法是什么?

【问题讨论】:

  • 您可以使用waitpidWNOHANG 选项来轮询子进程的状态。在读取子进程的输出时循环执行此操作,直到超时(或子进程退出)。
  • 此外,如果您仔细查看链接到的示例,它在子进程结束(或被杀死)后有一个 waitpid 调用,让您获得退出代码。
  • waitpid的第二个参数是状态。您可以使用WEXITSTATUS 宏从中获取返回码。
  • 在 WNOHAND 中使用 waitpid 似乎是一种低效且丑陋的解决方案。我不确定最后一次调用waitpid的目的是什么。让我们假设子进程没有终止然后它自然退出,所以在调用 waitpid 时进程不会消失吗?还是我在这里遗漏了什么?
  • 如果子进程退出,它将成为所谓的“僵尸”并在系统中徘徊(即使没有任何东西在运行),直到您调用 wait 函数之一来“reap "进程的状态。我认为您需要四处搜索并阅读更多有关 POSIX 系统(如 Linux 和 macOS)中的进程如何工作的信息。简而言之,如果您只是从 waitpid 调用中获取状态(而不是通过 NULL),那么您链接到的程序应该完全按照您想要的方式工作(关于超时)。

标签: c++ linux multithreading fork multiprocess


【解决方案1】:

你可以用sigtimedwait函数做#1和#2,用pipe做#3:

#include <unistd.h>
#include <signal.h>
#include <iostream>

int main() {
    // Block SIGCHLD, so that it only gets delivered while in sigtimedwait.
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGCHLD);
    sigprocmask(SIG_BLOCK, &sigset, nullptr);

    // Make a pipe to communicate with the child process.
    int child_stdout[2];
    if(pipe(child_stdout))
        abort();

    std::cout.flush();
    std::cerr.flush();
    auto child_pid = fork();
    if(-1 == child_pid)
        abort();

    if(!child_pid) { // In the child process.
        dup2(child_stdout[1], STDOUT_FILENO); // Redirect stdout into the pipe.
        std::cout << "Hello from the child process.\n";
        std::cout.flush();
        sleep(3);
        _exit(3);
    }

    // In the parent process.
    dup2(child_stdout[0], STDIN_FILENO); // Redirect stdin to stdout of the child.
    std::string line;
    getline(std::cin, line);
    std::cout << "Child says: " << line << '\n';

    // Wait for the child to terminate or timeout.
    timespec timeout = {1, 0};
    siginfo_t info;
    auto signo = sigtimedwait(&sigset, &info, &timeout);
    if(-1 == signo) {
        if(EAGAIN == errno) { // Timed out.
            std::cout << "Killing child.\n";
            kill(child_pid, SIGTERM);
        }
        else
            abort();
    }
    else { // The child has terminated.
        std::cout << "Child process terminated with code " << info.si_status << ".\n";
    }
}

输出:

Child says: Hello from the child process.
Killing child.

如果sleep 被注释掉:

Child says: Hello from the child process.
Child process terminated with code 3.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2021-08-27
    • 1970-01-01
    相关资源
    最近更新 更多