如何解决python的shared_memory自动删除的问题

最近用python (3.10的版本) 来写一个读取共享内存的程序,发现每次程序退出后会自动把这个共享内存给删掉,而实际没有调用任何close或del的方法,查阅了下资料,发现了如下bug:

Issue 38119: resource tracker destroys shared memory segments when other processes should still have valid access - Python trackerhttps://bugs.python.org/issue38119

研究了半天,找到一个解决办法
python 3.8 - Shared memory deleted at exit - Stack Overflowhttps://stackoverflow.com/questions/64102502/shared-memory-deleted-at-exit

具体代码如下:

from multiprocessing import shared_memory,resource_tracker

shm_name = '/test_share'

shm = shared_memory.SharedMemory(name=shm_name,create=False)

resource_tracker.unregister(f'/{shm_name}', "shared_memory")

  注:要在共享名称前还要加个符号/

注:使用PyInstaller打包运行会存在问题(可能跟resource_tracker有关),使用nuikta打包不会

恰好笔者有程序需要用pyinstaller打包,后来研究了一下,放弃使用这个python自带的shared_memory,改为直接使用ctypes访问shared memory的api, 具体代码可参考如下:

import ctypes
import mmap
import os
import stat
import sys


try:
    unicode
except NameError:
    unicode = str


rtld = ctypes.cdll.LoadLibrary(None)

_shm_open = rtld.shm_open
_shm_unlink = rtld.shm_unlink


def shm_open(name):
    if isinstance(name, bytes):
        name = ctypes.create_string_buffer(name)
    elif isinstance(name, unicode):
        name = ctypes.create_unicode_buffer(name)
    else:
        raise TypeError("`name` must be `bytes` or `unicode`")

    result = _shm_open(
        name,
        ctypes.c_int(os.O_RDWR | os.O_CREAT | os.O_EXCL),
        ctypes.c_ushort(stat.S_IRUSR | stat.S_IWUSR)
    )

    if result == -1:
        raise RuntimeError(os.strerror(ctypes.get_errno()))

    return result


def shm_unlink(name):
    if isinstance(name, bytes):
        name = ctypes.create_string_buffer(name)
    elif isinstance(name, unicode):
        name = ctypes.create_unicode_buffer(name)
    else:
        raise TypeError("`name` must be `bytes` or `unicode`")

    result = _shm_unlink(name)

    if result == -1:
        raise RuntimeError(os.strerror(ctypes.get_errno()))

 代码来源:https://gist.github.com/jakirkham/100a7f5e86b0ff2a22de0850723a4c5c

 用这个替换后,pyinstaller打包的程序是正常的。 

在 C# 中,你可以使用 `System.IO.Pipes` 命名空间中的 `NamedPipeServerStream` 和 `NamedPipeClientStream` 类来创建共享内存通信。这里是一个简单的例子展示了如何在服务器端和客户端之间共享数据: **服务器端(Producer.cs):** ```csharp using System; using System.IO.Pipes; class SharedMemoryServer { static NamedPipeServerStream pipeServer; public const string PipeName = "MySharedMemory"; static void Main() { try { pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.InOut, // 双向通信 ServerMode.Message | PipeTransmissionMode.Byte | PipeOptions.Asynchronous, NamedPipeClientStream.DefaultMaxinstances); pipeServer.WaitForConnection(); byte[] buffer = new byte[4096]; int bytesRead; Console.WriteLine("Server started, waiting for data..."); while ((bytesRead = pipeServer.Read(buffer, 0, buffer.Length)) > 0) { Console.WriteLine($"Received {bytesRead} bytes from client."); // 在此处处理接收到的数据 pipeServer.Write(buffer, 0, bytesRead); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } } ``` **客户端(Consumer.cs):** ```csharp using System; using System.IO.Pipes; class SharedMemoryClient { public static void Main() { try { string pipeName = "MySharedMemory"; using (var pipeClient = new NamedPipeClientStream(".", pipeName)) { pipeClient.Connect(); if (!pipeClient.IsConnected) throw new IOException("Failed to connect to the server."); byte[] buffer = new byte[4096]; Console.WriteLine("Connecting to server..."); Console.WriteLine("Enter some data to send:"); var input = Console.ReadLine(); Array.Resize(ref buffer, input.Length + 1); // 增加一用于null终止符的空间 buffer[buffer.Length - 1] = 0; // 设置null终止符 pipeClient.WriteByteCount(input.Length); pipeClient.WriteAsync(buffer, 0, input.Length).Wait(); pipeClient.ReadByteCount(); // 阅读服务器返回的字节数 pipeClient.EndRead(buffer, 0, buffer.Length); Console.WriteLine($"Sent {input.Length} bytes, received {BitConverter.ToString(buffer)}"); } } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } } ``` 在这个示例中,服务器等待客户端连接并接收数据,而客户端发送数据并在完成后读取响应。注意,实际应用中你需要添加适当的错误处理和数据解码/编码逻辑。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值