Python Ctypes выделяет память для функции C.

#python #memory-management #ctypes

#python #управление памятью #ctypes

Вопрос:

В настоящее время у меня есть функция обратного вызова python, которая вызывает функцию c с использованием библиотеки ctypes. Для функции c требуется указатель на структуру, например animal_info_s. Я создаю экземпляр структуры и передаю ее как указатель на функцию c, и она работает. Проблема, с которой я сталкиваюсь, заключается в том, что когда у меня есть несколько потоков, вызывающих обратный вызов, я обнаруживаю, что передаваемая обратно информация путается между потоками.

 class animal_info_s(ctypes.Structure):
    _fields_ = [('dog_type',          ctypes.c_uint16),
                ('cat_type',          ctypes.c_uint16),
                ('bird_type',         ctypes.c_uint16),
                ('epoch_time',        ctypes.c_uint16),
                ('more_information',  ctypes.c_uint16)]


_mod = ctypes.cdll.LoadLibrary('bbuintflib.dll')
animal_info_s = animal_info_s()
get_animal_data = _mod.get_animal_data
get_animal_data.argtypes = [ctypes.POINTER(animal_info_s)]
get_animal_data.restype =   ctypes.c_int

# Python Callback
def GetAnimalData():
    animal_info_p = animal_info_s
    res = get_animal_data(animal_info_p)
    if (res != 0):
        print("Failed to get animal info")
        return

    print ("Receive Time - %dnDog: %dnCat: %dnBird:%d" %(animal_info_p.epoch_time,
                                                            animal_info_p.dog_type,
                                                            animal_info_p.cat_type,
                                                            animal_info_p.bird_type))
  

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

Комментарии:

1. Я не эксперт по ctypes, но используете ли вы animal_info_p = animal_info_s in GetAnimalData для каждого потока? Это означало бы использование одного и того же экземпляра struct везде (и объяснило бы странное поведение). Разве вы не хотите animal_info_p = animal_info_s() вместо этого?

Ответ №1:

Следующая строка должна быть удалена. Он переопределяет имя animal_info_s как class animal_info_s экземпляр, который затем скрывает класс.

 animal_info_s = animal_info_s()
  

Следующая строка должна быть изменена с:

 animal_info_p = animal_info_s
  

Для:

 animal_info_p = animal_info_s()
  

Исходная строка создала другое имя для animal_info_s имени из первой ошибки, которое было единственным экземпляром, используемым в потоках. рекомендуемая строка создает новый экземпляр animal_info_s класса при каждом вызове обратного вызова.

Комментарии:

1. При создании нового экземпляра animal_info_s должен ли я освобождать всю используемую память или она обрабатывается Python? Python обычно обрабатывает это, но я беспокоюсь, что это особый случай (этот объект предназначен для C), и это может привести к утечке памяти где-нибудь.

2. Она освобождается Python, когда экземпляр выходит из области видимости в конце функции. Если функция C хранит ссылку на память, вам придется сохранять ссылку на объект в Python до тех пор, пока это необходимо функции C.