#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
inGetAnimalData
для каждого потока? Это означало бы использование одного и того же экземпляра 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.