Правильное отбрасывание указателей ctypes на память mmap в Python

У меня проблема, что я не могу правильно закрыть mmap-s в Python после того, как создал на них указатель. Мой вариант использования заключается в том, что я открываю файлы (обычно это UIO-устройства для работы с оборудованием, но проблема также возникает с обычными файлами), сопоставляю их память, а затем использую их в качестве буферов для ctypes-структур. Обычно это структуры или массивы данных. Минимальный пример выглядит так:

import ctypes as ct
import mmap
import os

fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map)

# Use the memory object to do things here

del memory
map.close()
os.close(fileno)

В этот момент все в порядке.

Однако иногда мне нужно вызвать некоторые функции библиотеки C, которым также нужен доступ к этой памяти, поэтому я должен передать указатель на них. Я создаю этот указатель, используя:

ptr = ct.cast(memory, ct.c_void_p)

Все это работает очень хорошо, кроме одного. Как только я создаю такой указатель, я уже не могу закрыть карту памяти. Возьмите этот немного расширенный пример:

import ctypes as ct
import mmap
import os

fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map)

# Use the memory object to do things here
ptr = ct.cast(memory, ct.c_void_p)
del ptr

del memory
map.close()
os.close(fileno)

Выполнение этого приводит к следующему исключению:

Traceback (most recent call last):
  File "pointer_test.py", line 14, in <module>
    map.close()
BufferError: cannot close exported pointers exist

Process finished with exit code 1

Я провел некоторый анализ (используя gc.get_referrers) того, что ссылается на экземпляр map, и оказалось, что экземпляр memoryview все еще существует. В конце концов, это отслеживается до массива ctypes:

[<__main__.c_uint_Array_8192 object at 0x7f954bd1e0>,
 [{547965620704: <__main__.c_uint_Array_8192 object at 0x7f954bd1e0>,
   'ffffffff': <memory at 0x7f95621a08>},
  [<memory at 0x7f95621a08>,
   [<managedbuffer object at 0x7f95746d08>,

Тем не менее, это не очень помогает мне. Я хотел бы знать, как я могу избавиться от этого указателя. Я знаю, что это, вероятно, не совсем безопасно, поскольку я, конечно, всегда мог бы где-то иметь копию этого указателя. Но полное предотвращение закрытия mmap после создания указателя также не кажется хорошей идеей. Кто-нибудь знает, как я могу убедить Python, что я отбросил все указатели и теперь можно безопасно закрыть mmap?


person jan    schedule 16.11.2018    source источник
comment
Сделал такой же тест, как и вы, и получил тот же результат. Я думал, что это просто ссылка, хранящаяся где-то в python, поэтому я просто сделал: import gc и gc.collect() и сразу после этого попытался закрыть файл с отображением памяти: это сработало... Я не вижу другого способа сказать python, что на мем карте нет рефов :(   -  person Neitsa    schedule 20.11.2018


Ответы (1)


найдите экземпляр memoryview и сначала вызовите memoryview-instance.release(), затем вы можете закрыть экземпляр mmap.

person Majorli    schedule 10.05.2019