Python与C++子进程自定义Pipe通信失败排查及方案咨询
问题描述
我们的测试场景如下:创建一个Pipe,启动C二进制程序作为子进程(将Pipe的写文件描述符作为参数传递给子进程),等待C程序向Pipe写入数据。由于stdout/stderr已用于读取C++子进程的输出和错误信息,因此未使用这两个通道进行本次通信。
Python代码
import os import subprocess def main(): r, w = os.pipe() cpp_path = "../bin/cpp_engine" cpp_process = subprocess.Popen([cpp_path, "-v", "-p", str(w)]) r = os.fdopen(r) stg = r.read() print("test reads : ", stg) cpp_process.kill() if __name__ == "__main__": main()
C++代码(用于向Pipe写入数据)
#include <lyra/lyra.hpp> int main(int argc, char * argv[]) { auto intgTestPipe = -1; auto cli = lyra::cli(); cli.add_argument( lyra::opt(verboseFlag).name("-v").name("--verbose").help("enable verbose flag") | lyra::opt(intgTestPipe, "Integraion test Pipe") .name("-p") .name("--pipe") .help("Integration test pipe to communicate")); auto result = cli.parse({argc, argv}); if (!result) { std::cout << "Error in command line: " << result.message() << std::endl; return 1; } std::cout << intgTestPipe << " " << typeid(intgTestPipe).name() << std::endl; if (intgTestPipe != -1) { std::cout << "in intgTestPipe" << std::endl; auto fp = fdopen(intgTestPipe, "w"); std::string msg = "sending message\n"; if (fp != NULL) { fputs(msg.c_str(), fp); } else { std::cout << "Invalid file pointer" << std::endl; } fclose(fp); return 0; } }
运行结果
运行Python测试时,程序在读取Pipe时阻塞,C++程序输出如下:
4 i in cpp intgTestPipe Invalid file pointer
疑问
不清楚为何已传递Pipe的写文件描述符,却仍出现无效文件指针的问题。请问该程序存在什么问题?或者有哪些不依赖stdin/stdout/stderr的Python与C++子进程通信方案?
解答
程序存在的问题
- 文件描述符未被子进程继承:Unix系统下
subprocess.Popen默认开启close_fds=True,会关闭除stdin/stdout/stderr外的所有文件描述符,导致子进程拿到的写端fd已失效。解决方法是在创建子进程时显式设置close_fds=False:cpp_process = subprocess.Popen([cpp_path, "-v", "-p", str(w)], close_fds=False) - C++代码存在未定义变量:
verboseFlag未声明,编译会报错,需补充定义:bool verboseFlag = false; - 空指针解引用风险:若
fdopen失败,后续的fclose(fp)会触发空指针访问,需调整逻辑仅在fp有效时执行关闭操作:if (fp != NULL) { fputs(msg.c_str(), fp); fclose(fp); } else { std::cout << "Invalid file pointer" << std::endl; } - Python读取逻辑的阻塞问题:
r.read()会阻塞到管道写端完全关闭,确保C++程序写完后正确关闭写端即可解除阻塞。
替代通信方案(不依赖stdin/stdout/stderr)
- Unix域套接字:支持双向通信,Python和C++均可通过套接字API直接实现,比管道更灵活。
- 共享内存:通过
mmap(Python的mmap模块、C++的<sys/mman.h>)实现内存共享,适合大数据传输,但需搭配信号量等同步机制。 - 消息队列:使用POSIX或System V消息队列,Python可借助
posix_ipc库,C++直接调用系统API。 - 命名管道(FIFO):创建磁盘上的管道文件,双方通过读写该文件通信,适合非父子进程间的通信场景。
内容的提问来源于stack exchange,提问作者kadina
相关产品推荐
相关产品推荐

