从 Python 子进程中的 stdin 读取挂起在 C++/Python IPC 中

Reading from stdin in Python subprocess hangs in C++/Python IPC

本文关键字:Python C++ 挂起 IPC stdin 子进程 读取      更新时间:2023-10-16

我正在开发一个C++应用程序,该应用程序启动一个Python子进程并尝试在父(C++)和子(Python)之间建立通信。特别是,我正在编写Python部分,以便与我没有编写且无法更改的C++应用程序集成。我已经实现了一个套接字解决方案来处理通信,但我还需要支持使用管道的通信。

我的问题是我可以从 Python 写入 stdout,并且消息由C++应用程序接收。但是,Python 子进程无法读取父进程发送的消息。我试图推断我认为与描述问题最相关的代码部分:

C++

void startSubprocess(char* program, char** arguments)
{
    int p_stdout;
    int p_stdin;
    int p_stderr;
    int out[2];
    int in[2];
    int err[2];
    char** arguments;
    char* program;
    pipe(out);
    pipe(in);
    pipe(err);
    posix_spawn_file_actions_init(&action);
    posix_spawn_file_actions_addclose(&action, out[1]);
    posix_spawn_file_actions_addclose(&action, in[0]);
    posix_spawn_file_actions_addclose(&action, err[0]);
    posix_spawn_file_actions_adddup2(&action, out[0], 0);
    posix_spawn_file_actions_adddup2(&action, in[1], 1);
    posix_spawn_file_actions_adddup2(&action, err[1], 2);
    std::vector<char *> vars_c(vars.size() + 1); 
    for (std::size_t i = 0; i != vars.size(); ++i) {
        vars_c[i] = &vars[i][0];
    }
    vars_c[vars.size()] = NULL;
    string cwd = __getcwd();
    if (directory.size() > 0)
        chdir(directory.c_str());
    if (posix_spawnp(&pid, program, &action, NULL, arguments, vars_c.data())) {
        cleanup();
        pid = 0;
        if (directory.size() > 0) chdir(cwd.c_str());
        return false;
    }
    if (directory.size() > 0) chdir(cwd.c_str());
    p_stdin = out[1];
    p_stdout = in[0];
    p_stderr = err[0];
}
void write(const char* buf, int len)
{
    write(p_stdout, buf, len);
}
void read(char* buf, int len)
{
    read(p_stdin, buf, len);
}

def writeMsg(msg):
    sys.stdout.write(msg)
    sys.stdout.flush()

def readMsg():
    msg = sys.stdin.read()

当我运行应用程序时,父进程 (C++) 读取 Python 子进程发送的消息。之后,Python 子进程无法从 sys.stdin 读取。它永远等待到超时。

当我运行C++应用程序时,我可以看到 out = [3,4] 和 in=[5,6] 所以 p_stdin=6 和 p_stdout=3。我正在 Ubuntu 14.04 中测试该应用程序。

我一直在尝试其他几种方法(使用os.fdopen和os.read),但没有成功。欢迎任何解决此问题的建议。谢谢!

编辑

我意识到我跳过了一些重要信息来理解问题。主应用程序和 Python 子进程需要连续通信和读写消息,以便在循环中发送和接收,直到终止。代码看起来像这样(仅用于描述目的):

C++

int communicate()
{
    // skip var init etc
    // launch subprocess
    startSubprocess(program, arguments);
    while(1)
    { 
        // read message sent by subprocess
        read(msg, len);  
        if(msg == "quit")
            break;
        // part of the code that generates msg2
        //  send a message to subproc  
        write(msg2, len2);
    } 
    return 1;     
}

def communicate():
    while True:
        # generate msg to send to C++
        writeMsg(msg)
        msgRcv = readMsg()
        if msgRcv == 'quit':
            break
    return         

我已经意识到 sys.stdin.read() 在返回消息之前挂起到 EOF。通过将 msg = sys.stdin.read() 替换为

msg = sys.stdin.readline() 

我的应用程序按预期工作。应用程序发送的消息用换行符""分隔,因此这种方法对我有用。在其他情况下,我认为一次阅读一个字符使用

msg += sys.stdin.read(1) 

将避免程序挂起等待 EOF。

关于阅读和阅读行之间的这种差异,已经有几个答案。不幸的是,在我的测试中,当我尝试阅读时,客户端在读取之前被父进程终止。