gpt4 book ai didi

python - 为什么调用守护进程时 Python check_output() 不返回?

转载 作者:行者123 更新时间:2023-11-30 05:32:13 25 4
gpt4 key购买 nike

我有一个 Python v3.4 应用程序,它使用 check_output() 调用调用 fork() 的 C++ 应用程序,原始进程退出,子进程继续。似乎 check_output() 也在等待子进程,而不是在主进程返回并表示守护进程已成功启动后返回。

我是否需要更改我在 C++ 中 fork() 的方式,或者 Python check_output() 调用是否需要以某种方式被告知仅等待父进程退出?我是否需要在 C++ 中执行第二个 fork() 作为 described here


这里是展示问题的 Python 精简版:

#! /usr/local/bin/python3

import logging
import argparse
from subprocess import CalledProcessError, check_output, STDOUT

ARGS = ["user@hostname:23021:"]

if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Try launching subprocess")
parser.add_argument("exec", type=str, help="the exec to run")
args = parser.parse_args()

logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')

cmd_list = [args.exec] + ARGS
logging.info(str(cmd_list))

try:
output = check_output(cmd_list,
stderr=STDOUT,
universal_newlines=True)
logging.info("Exec OK with output:")
logging.info(output)
except CalledProcessError as e:
logging.info("Exec Not OK with output:")
logging.info(str(e))

这是用于守护 C++ 应用程序的 C++ 代码:

void
daemonize()
{
// This routine backgrounds the process to run as a daemon.
// Returns to caller only if we are the child, otherwise exits normally.
if (getppid() == 1) {
return; // Leave if we're already a daemon
}

// Create the backgrounded child process.
const pid_t parent = getpid();
const pid_t pid = fork();
CSysParamAccess param;
const string progName(param.getProgramKindName());

::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);

if (pid < 0) {
cerr << "Error: " << progName << " failed to fork server. Aborting."
<< endl; // inform the client of the failure

exit(appExit::failForkChild); // Error. No child created.
} else if (pid > 0) {
// We're in the parent. Optionally print the child's pid, then exit.
if (param.getDebug()) {
clog << "Successful fork. The Application server's (" << progName
<< ") pid is: " << pid << "(self) from parent " << parent << endl;
}

::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);

exit(appExit::normal);
}

::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);

// Here only in the child (daemon).
if (-1 == setsid()) { // Get a new process group
cerr << "Error: Failed to become session leader while daemonising - errno: "
<< errno;

exit(appExit::failForkChild); // Error. Child failed.
}

signal(SIGHUP, SIG_IGN); // Per example.

// Fork again, allowing the parent process to terminate.
const pid_t midParent = getpid();
const pid_t grandChildPid = fork();

if (grandChildPid < 0) {
cerr << "Error: Failed to fork while daemonising - errno: " << errno;

exit(appExit::failForkChild); // Error. GrandChild failed.
} else if (grandChildPid > 0) {
// We're in the parent. Optionally print the grandchild's pid, then exit.
if (param.getDebug()) {
clog << "Successful second fork. The Application server's (" << progName
<< ") pid is: " << grandChildPid << "(self) from parent "
<< midParent << endl;
}

::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);

exit(appExit::normal);
}

// Here only in the grandchild (daemon).
appGlobalSetSignalHandlers();

// Set the current working directory to the root directory.
if (chdir("/") == -1) {
cerr <<
"Error: Failed to change working directory while daemonising - errno:"
<< errno;

exit(appExit::failForkChild); // Error. GrandChild failed.
}

// Set the user file creation mask to zero.
umask(0);

//close(STDIN_FILENO); // Cannot close due to assertion in transfer.cpp
// Theoretically, we would reopen stderr and stdout using the log file.
::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);

// We only return here if we're the grandchild process, the Application
// server. The summoner exited in daemonize().
clog << "Application " << param.getProgramKindName()
<< " (" << appGlobalProgramName() << ") successfully started." << endl;
}

它在使用 echo 调用时有效,但在我的 C++ 应用程序中失败:

> stuckfork.py echo
2016-02-05 10:17:34 - ['echo', 'user@hostname:23021:']
2016-02-05 10:17:34 - Exec OK with output:
2016-02-05 10:17:34 - user@hostname:23021:

> stuckfork.py flumep
2016-02-05 10:17:53 - ['flumep', 'user@hostname:23021:']
C-c Traceback (most recent call last):
File "/home/user/Bin/Bin/stuckfork.py", line 26, in <module>
universal_newlines=True)
File "/usr/local/lib/python3.4/subprocess.py", line 609, in check_output
output, unused_err = process.communicate(inputdata, timeout=timeout)
File "/usr/local/lib/python3.4/subprocess.py", line 947, in communicate
stdout = _eintr_retry_call(self.stdout.read)
File "/usr/local/lib/python3.4/subprocess.py", line 491, in _eintr_retry_call
return func(*args)
KeyboardInterrupt
>

我已将问题缩小到我的一个 C++ 静态构造函数正在做一些导致启动过程失效的事情,这就是 Python 仍在等待的原因。现在分看是哪个。

最佳答案

正确的解决方案是找到正确的文件描述符,将输出从 fork 的 C++ 子级通过管道传输到 python,然后关闭它。

现在您可以尝试在 C++ 子进程中或在调用子进程之前(就在 fork() 之后)close(1) SYSTEM CALL。这将向 python 发出信号,停止尝试从 child 那里读取信息。

我不确定这是否可行,因为您发布的代码还不够。

关于python - 为什么调用守护进程时 Python check_output() 不返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35214623/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com