尝试通过 Process Pipe 发送/接收到 python 包装器,C++ 代码

Posted

技术标签:

【中文标题】尝试通过 Process Pipe 发送/接收到 python 包装器,C++ 代码【英文标题】:Attempting to send/receive over Process Pipe to python wrapper, c++ code 【发布时间】:2020-05-09 00:42:00 【问题描述】:

我有一个包含一些 c++ 代码的 python 包装器。它是一个函数,我从我的 python 代码中设置为一个进程。它是一个 while 语句,我需要设置它何时应该关闭的条件。

对于这种情况,while 语句很简单。

while(TERMINATE == 0)

我有正在从 while 循环中发回的数据。我正在使用 pipe() 创建“输入”和“输出”对象。创建进程时,我将“输出”对象发送给函数。

fxn = self.FG.do_videosequence
(self.inPipe, self.outPipe) = Pipe()
self.stream = Process(target=fxn, args=(self.outPipe,))
self.stream.start()

正如我所提到的,在包装器中,我可以将数据发送回 python 脚本

PyObject *send = Py_BuildValue("s", "send_bytes");
PyObject_CallMethodObjArgs(pipe, send, temp, NULL);

这很好用。但是,我在向包装器中的 C++ 代码发送消息时遇到问题,告诉循环停止。

我想我会做的只是检查 poll(),因为这就是我在 python 脚本方面所做的。我想保持简单。当系统看到有来自 python 脚本的传入信号时,它会设置 TERMINATE = 1。所以我写了这个。

PyObject *poll = Py_BuildValue("p", "poll");

正如我期待 python 函数 poll() 的真假。我认为“p”是理想的,因为它会将 true 转换为 1,将 false 转换为 0。

在我的循环中

if(PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL))
            TERMINATE = 1;

我想使用 poll() 作为它的非阻塞,就像 recv() 一样。这样我就可以继续我的其他工作,并且每个周期检查一次 poll()。

但是,当我从 python 脚本发送信号时,它永远不会跳闸。

self.inPipe.send("Hello");

我不确定断开连接在哪里。当我打印 poll() 请求时,我一直得到 0 。我要么没有正确调用它,它只是默认为 0。或者我实际上并没有生成一个信号来触发 poll() 调用。因此它始终为 0。

有没有人知道我做错了什么?

*****更新******

我发现了一些其他信息。

PyObject *poll = Py_BuildValue("p", "poll");

应该是

PyObject *poll = Py_BuildValue("s", "poll");

当我传递一个字符串作为对调用它的函数的引用时,应该将其引用为字符串。它与返回类型无关。

从那里返回

PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL)

是一个 pyobject,因此需要根据 pyobject 检查它。比如打电话给

PyObject_IsTrue

判断它的真假。我将对我的代码进行更改,如果我有解决方案,我会用答案更新帖子。

【问题讨论】:

我对你的代码感到困惑。您确实意识到您需要两个管道……即四个文件描述符……来处理双向通信。正确的?调用 pipe()(系统调用)返回的描述符对包括管道的两端;一个由父进程使用,另一个由子进程使用。两次调用管道,父级各保持一种类型,子级使用每个类型的相应相对端,为您提供双向管道对。还要确保您的 I/O 至少在每一端都是非阻塞的!否则很可能出现死锁。 @JimDennis 嗨,谢谢。我已经更新了我的帖子以反映您的想法。我还发布了一些我能够找到的新信息。 @JimDennis Jim,也许你可以澄清一下。我刚刚检查了 python 文档,它说 pipe() 函数默认为两种方式,双工。它给出的示例似乎表明不需要四个描述符。 docs.python.org/3.4/library/… 注意:我特别提到了 Unix/Linux 系统调用 pipe() ...但 Python os.pipe() 具有相似的语义:docs.python.org/3/library/os.html?highlight=os.pipe#os.pipe。我不知道你在读什么文档。 (它们是针对 C 级 Python API 的吗?)但也许这个讨论对您有用:claytonrichey.com/post/c-cpp-python-pipe 我的部分困惑是我几乎从未使用过 Python 的 C API; 【参考方案1】:

所以我已经找到了解决方案。最后我犯了两个错误。 第一个错误是当我创建对我正在调用的 python 函数的 pyobject 引用时。我弄错了信息,在阅读上下文之前插入了一个“p”的想法。所以

PyObject *poll = Py_BuildValue("p", "poll");

应该是

PyObject *poll = Py_BuildValue("s", "poll");

第二个错误是我如何处理

的返回值
PyObject_CallMethodObjArgs(pipe, poll, NULL, NULL)

虽然它调用了一个python对象是真的,但它不是返回一个简单的真假值,而是一个python对象。所以我特别需要处理python对象,通过调用

PyObject_IsTrue(Pyobject o)

以 poll() 请求的返回作为参数。我现在能够从包装器中包含的 python 脚本和 C api 发送/接收。

【讨论】:

以上是关于尝试通过 Process Pipe 发送/接收到 python 包装器,C++ 代码的主要内容,如果未能解决你的问题,请参考以下文章

如何将消息/数据从广播接收器(process1)发送到android中的服务线程(process2)?

tcp连接时,BROKEN PIPE错误的原因以及解决方法

管道“地址系统”

pipe forming process

python Pipe 双管道通信

无法接收 Vue 通过 axios 发送到 PHP 的 Post 数据