我正在编写一个接口,以允许用 C 编写的主程序和用 python 编写的扩展脚本之间进行通信,并在单独的 python 解释器进程中运行。该接口使用 UNIX 套接字来处理少量数据,使用 POSIX 共享内存来处理大型数组。 C 程序处理共享内存的所有创建、资源跟踪和最终取消链接。
这在 Linux 上完美运行。我可以使用 shm 按预期在两个进程之间传输数据。
然而,当完全相同的代码在 MacOS 上运行时,尽管它运行时没有错误,但当从另一个进程读取到填充内存的进程时,共享内存总是充满零。例如如果我从 C 将图像数据写入 shm,并从 python 读取它,则全部为零。如果我从 python 将图像数据写入 shm 并从 C 读取它,那么它又全为零。 我在 C 中创建 shm,如下所示:(为了清楚起见,删除了一些错误处理行)
void *shm_ptr = NULL;
snprintf(shm_name_ptr, 30, "/%08x%08x%08x%04x", my_random_int(), my_random_int(), my_random_int(), my_random_int());
debug_print("shm name: %s\n", shm_name_ptr);
*fd = shm_open(shm_name_ptr, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
ftruncate(*fd, aligned_size) == -1);
shm_ptr = mmap(NULL, (size_t) aligned_size, PROT_READ | PROT_WRITE,
MAP_SHARED, *fd, 0);
*shm_ptr_ptr = shm_ptr;
然后详细信息通过套接字传递给python。我没有重现它的细节,因为代码相当长,对于 Windows 等使用#ifdefs,但是套接字机制确实有效,我可以打印 shm 名称,因为它是在 C 中创建的,也是在 python 中接收的表明它们是相同的:
shm name: /b6c31655f708d0e20760b60bc483
SHM allocation: Original size: 25941632, Aligned size: 25944064, Page size: 4096
Truncating shm file to 25941632 bytes
log: b'/b6c31655f708d0e20760b60bc483'
(第一行文本是从 C 打印的,最后一行是从 python 打印的。)
我在 python 中使用的包装类中的
__init__
函数来打开 shm,如下所示:
class SharedMemoryWrapper:
"""
Wrapper class to handle shared memory creation and cleanup across platforms.
"""
def __init__(self, name: str, size: int):
self.name = name
self.size = size # Store intended size separately
self._shm = None
try:
# First try to attach to existing shared memory
self._shm = shared_memory.SharedMemory(name=self.name)
unregister(self._shm._name, "shared_memory")
except FileNotFoundError:
# If it doesn't exist, create new shared memory
print("Existing SHM not found, creating a new one...")
self._shm = shared_memory.SharedMemory(name=self.name, create=True, size=self.size)
(之所以存在
unregister()
调用,是因为 SHM 始终由 C 程序分配、跟踪和清理,并传递给 python 程序,因此当 python 脚本退出时,这会抑制有关 shm 泄漏的警告消息。)
一旦通过套接字接收到名称和大小,共享内存对象就会使用
SharedMemoryWrapper(name=name_from_socket, size=size_from_socket)
进行初始化
在 Linux 上,try 块有效并且 shm 已正确打开,但是在 MacOS 上,我看到消息“未找到现有 SHM,正在创建一个新的...”
请有人解释一下 MacOS 的不同之处,以及如何修复它以便正确打开现有的 shm?
我是 OP 的同事,已经调查了我们遇到的问题。
在C端创建共享内存对象时,在其名称中使用前导斜杠:
int fd = shm_open("/mem", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
在 Python 端访问它时,不要使用前导斜杠,因为它是 在 POSIX 系统上自动添加的:
shm = shared_memory.SharedMemory(name="mem", create=False)
现在 Python 能够找到该对象了。