【问题标题】:How to use shared memory in python and C/C++如何在 python 和 C/C++ 中使用共享内存
【发布时间】:2018-03-05 04:57:21
【问题描述】:

我正在尝试修改 python 程序,以便能够使用共享内存与 C++ 程序进行通信。 python程序的主要职责是从位于共享内存中的输入队列中读取一些视频帧,对视频帧执行一些操作并将其写回共享内存中的输出队列。

我相信我需要完成的事情很少,如果有人能对此有所了解,那就太好了:

  1. 共享内存:在 C/C++ 中,您可以使用 shmgetshmat 等函数来获取指向共享内存的指针。在 python 中处理这个问题的等效方法是什么,以便 python 和 C++ 程序可以使用同一块共享内存?

  2. 同步:因为这涉及到多处理,我们需要某种锁定机制用于 C++ 和 python 程序中的共享内存。我如何在 python 中做到这一点?

非常感谢!

【问题讨论】:

  • 一个帖子中的许多问题通常都没有得到回答,我建议将您的帖子分成几个帖子,并在每个帖子中提出一个特定的问题。
  • 在他看来,另一件事是说他是初学者可能会导致他失去高质量的答案,因为我们会假设他对该主题一无所知,因此回答了什么范围将受到限制。
  • @eyllanesc 根据建议删除了与signal 相关的问题。顺便问一下,您对此有什么好的答案吗?
  • @eyllanesc 我猜有些人认为提到自己是初学者会减少反对票,因为现在人们倾向于对像这样的一般性问题投很多反对票,以赚取徽章和名声。但代价是,正如你所说,他会失去一些高质量的答案。
  • @HeiHei 我没有好的答案,相反,我对一些好的答案很感兴趣,不是每个人都会给你答案,像我这样的人会帮助你给你建议以改进你的问题。我们都为自己的方式提供帮助,因为我们是社区的一部分。

标签: python c++ synchronization multiprocessing


【解决方案1】:

也许shmgetshmat 不一定是最适合您使用的接口。在我从事的一个项目中,我们使用内存映射文件通过 C 和 Python API 提供对守护进程的访问,这为我们提供了一种非常快速的数据访问方式

操作的顺序有点像这样:

  • 客户端发出door_call() 告诉守护进程创建共享内存区域
  • 守护进程安全地创建一个临时文件
  • 守护进程open()s 然后mmap()s 那个文件
  • 守护进程通过door_return()将文件描述符传回客户端
  • 客户端 mmap()s 文件描述符并将结构中连续放置的变量与该 fd 相关联
  • 客户端在需要时对这些变量执行所需的任何操作。
  • 守护程序从共享区域读取数据并进行自己的更新(在我们的例子中,将值从该共享区域写入日志文件)。

我们的客户使用库来处理上述前 5 个步骤;该库带有 Python 包装器,使用 ctypes 来准确公开所需的函数和数据类型。

对于您的问题空间,如果只是写入输出队列的 python 应用程序,那么您可以跟踪仅在 python 应用程序中处理了哪些帧。如果您的 python 和 c++ 应用程序都在写入输出队列,那么这会增加您的难度,也许重构整个应用程序架构将是一项不错的投资。

【讨论】:

  • 感谢您的建议。请您简要解释一下我如何自己实现door_call()door_return(),因为它们显然是Oracle 的功能?是一种信号,unix socket还是别的什么?
  • 我花了一些时间看了一下CPython,发现我们可以直接使用Py_xxx直接调用python函数。将视频帧直接传递给 Py_xxx(frame) 作为参数而不是使用共享内存,并从该函数的返回值中获取处理后的帧会更有效吗?或者这有什么缺点?
  • 关于door_call()door_return() 的问题是:我不确定这些功能是否已完全为Linux 实现; rampant.org/doors/index.html 有点过时了。使用 unix 域套接字可能会更好。
  • CPython 很可能会为您提供所需的功能。您需要根据您的用例和功能要求评估它的效率(坦率地说,优雅)。
【解决方案2】:

有点,有点共享内存。所以不完全是 OP 想要的。

这适用于内存映射文件。我不以任何方式声称高速或高效。这些只是为了展示它的工作示例。

 $ python --version
 Python 3.7.9

 $ g++ --version
 g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

C++ 端只监控它需要的值。 Python 端只提供值。

注意:文件名“pods.txt”在C++和python代码中必须一致。

#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
int main(void)
  {
  // assume file exists
  int fd = -1;
  if ((fd = open("pods.txt", O_RDWR, 0)) == -1)
     {
     printf("unable to open pods.txt\n");
     return 0;
     }
  // open the file in shared memory
  char* shared = (char*) mmap(NULL, 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

  // periodically read the file contents
  while (true)
      {
      printf("0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", shared[0], shared[1], shared[2], shared[3], shared[4], shared[5],           shared[6], shared[7]);
      sleep(1);
      }

   return 0;
   }

python方面:

import mmap
import os
import time
 
fname = './pods.txt'
if not os.path.isfile(fname):
    # create initial file
    with open(fname, "w+b") as fd:
         fd.write(b'\x01\x00\x00\x00\x00\x00\x00\x00')

# at this point, file exists, so memory map it
with open(fname, "r+b") as fd:
    mm = mmap.mmap(fd.fileno(), 8, access=mmap.ACCESS_WRITE, offset=0)

    # set one of the pods to true (== 0x01) all the rest to false
    posn = 0
    while True:
         print(f'writing posn:{posn}')

         # reset to the start of the file
         mm.seek(0)
 
         # write the true/false values, only one is true
         for count in range(8):
             curr = b'\x01' if count == posn else b'\x00'
             mm.write(curr)

         # admire the view
         time.sleep(2)

         # set up for the next position in the next loop
        posn = (posn + 1) % 8

    mm.close()
    fd.close()

要在终端 #1 中运行它:

 a.out  # or whatever you called the C++ executable
 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00
 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00
 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00
 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00

即由于 C++ 代码中的 sleep(2),您应该会看到 0x01 每隔几秒移动一步。

在 2 号航站楼:

python my.py  # or whatever you called the python file
writing posn:0
writing posn:1
writing posn:2

即您应该会看到位置从 0 到 7 再次变回 0。

【讨论】:

    猜你喜欢
    • 2018-03-19
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 2013-02-14
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    相关资源
    最近更新 更多