向新进程传递SharedMemory时触发FileNotFoundError问题排查
问题背景
我开发了一个多进程应用,需要在进程间传递Numpy数组,计划通过SharedMemoryManager.SharedMemory()让数组指向同一共享内存缓冲区,并用锁避免竞态条件。
创建进程代码
buffer = self.data_manager.SharedMemory(size=(w * h * c)) queue = self.data_manager.Queue() lock = self.data_manager.Lock() stop_event = self.data_manager.Event() frame_buffer = np.ndarray( (h, w, c), dtype=np.uint8, buffer=buffer.buf, ) proc = Process( target=run_camera, name=camera_request.name, kwargs={ "command_queue": queue, "lock": lock, "stop_event": stop_event, "shared_buffer": buffer, # 其他参数 }, ) proc.start()
目标函数代码
def run_camera( command_queue: Queue[CameraCommand], lock: Lock, stop_event: Event, shared_buffer: shared_memory.SharedMemory, # 其他参数 ) -> None: frame_buffer = np.ndarray( (h, w, c), dtype=np.uint8, buffer=shared_buffer.buf, ) # 对数组进行操作
触发的错误
启动新进程后立即抛出以下错误:
Traceback (most recent call last): File "", line 1, in
File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\spawn.py", line 116, in spawn_main
exitcode = _main(fd, parent_sentinel)
File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\spawn.py", line 126, in _main
self = reduction.pickle.load(from_parent)
File "C:\path\to\Miniconda3\envs\trumpf\lib\multiprocessing\shared_memory.py", line 161, in init
h_map = _winapi.OpenFileMapping( FileNotFoundError: [WinError 2] The system cannot find the file specified: 'wnsm_3ab8096f'
特殊现象:在proc.start()行设置断点,触发后继续运行则无错误,初步判断是时序问题,但测试time.sleep()未解决。
问题原因与解决方法
核心原因
Windows系统下,SharedMemory对象依赖系统级的文件映射实现。如果父进程中创建的SharedMemory对象被Python垃圾回收机制过早回收,对应的文件映射会被提前关闭,子进程启动时就找不到目标文件映射,从而抛出错误。断点暂停时父进程执行停滞,SharedMemory对象不会被回收,因此子进程能正常连接。
具体解决方案
保留共享内存对象引用
在父进程中,将buffer对象存入全局列表或类实例属性,避免被垃圾回收:# 在类初始化时添加存储属性 self.active_shared_buffers = [] # 创建buffer后加入列表 self.active_shared_buffers.append(buffer)待子进程退出后,再从列表中移除并清理该对象。
传递共享内存名称而非对象
避免直接序列化SharedMemory对象,改为传递其name属性,让子进程主动连接:- 修改进程创建代码:
proc = Process( target=run_camera, name=camera_request.name, kwargs={ "command_queue": queue, "lock": lock, "stop_event": stop_event, "shared_memory_name": buffer.name, "frame_shape": (h, w, c), "frame_dtype": np.uint8, # 其他参数 }, ) - 修改目标函数:
def run_camera( command_queue: Queue[CameraCommand], lock: Lock, stop_event: Event, shared_memory_name: str, frame_shape: tuple, frame_dtype: np.dtype, # 其他参数 ) -> None: shared_buffer = shared_memory.SharedMemory(name=shared_memory_name) try: frame_buffer = np.ndarray(frame_shape, dtype=frame_dtype, buffer=shared_buffer.buf) # 对数组进行操作 finally: # 子进程仅关闭连接,不释放共享内存,由父进程负责清理 shared_buffer.close()
- 修改进程创建代码:
显式控制共享内存生命周期
父进程需等待子进程完全退出后,再清理共享内存:# 等待子进程结束 proc.join() # 关闭并释放共享内存 buffer.close() buffer.unlink() # 从引用列表中移除 self.active_shared_buffers.remove(buffer)
内容的提问来源于stack exchange,提问作者Roland Deschain

