проблема с обратным вызовом в python (ctypes) - PullRequest
0 голосов
/ 11 апреля 2020

Привет, у меня проблема с CTYPES в python. У меня есть готовая библиотека DLL с некоторым обратным вызовом. На swift все работает, но у меня есть некоторые проблемы в python.

Python:

def set_up_callback(self):
    self.lib.set_callback(self.callback1)

@CFUNCTYPE(None, c_float, c_float, c_float, c_uint64)
def callback1( a, b, c, time):
    print(a, b, c, time)

c ++ объявление обратного вызова

typedef void(*callbackType)(float, float, float, uint64_t, void*);
        callbackType callback;

void* context;

c ++ init

void setCallback(callbackType callback, void* context) {

        this->context = context;
        this->callback = callback;
}

c ++ индукция

callback(1.5f, 2.4f, 1.3f, timestamp, context);

shared.h

extern "C" void SHARED_EXPORT set_callback(callbackType callback, void* context);

, и это хорошо работает, но я хотел бы иметь self В функции обратного вызова, поэтому я пытаюсь это

def set_up_callback(self):

    callback_type = CFUNCTYPE(None, c_float, c_float, c_float, c_uint64)

    callback = callback_type(self.callback1)

    self.lib.set_callback(callback)

def callback1(self, a, b, c, time):
    print(a, b, c, time)

и с этой попыткой у меня появляется ошибка Segmentation fault: 11

Заранее спасибо за помощь

1 Ответ

1 голос
/ 11 апреля 2020

В set_up_callback, callback - это локальная переменная, которая выходит из области видимости после вызова self.lib.set_callback(callback). Вы должны сохранить ссылку на callback на весь срок жизни, когда она может быть вызвана, поэтому сохраните ее как переменную-член экземпляра класса.

Рабочая демонстрация:

демонстрация. cpp

#include <time.h>
#include <stdint.h>

#if defined(_WIN32)
#   define API __declspec(dllexport)
#else
#   define API
#endif

typedef void(*CALLBACK)(float, float, float, uint64_t, void*);

CALLBACK g_callback;

extern "C" {

API void set_callback(CALLBACK callback) {
    g_callback = callback;
}

API void demo(void* context) {
    if(g_callback)
        g_callback(1.5f, 2.4f, 1.3f, time(nullptr), context);
}

}

demo.py

from ctypes import *
from datetime import datetime

CALLBACK = CFUNCTYPE(None,c_float,c_float,c_float,c_uint64,c_void_p)

class Demo:
    def __init__(self):
        self.lib = CDLL('./demo')
        self.lib.set_callback.argtypes = CALLBACK,
        self.lib.set_callback.restype = None
        self.lib.demo.argtypes = c_void_p,
        self.lib.demo.restype = None
        self.set_up_callback()

    def callback(self,a,b,c,timestamp,context):
        print(a,b,c,datetime.fromtimestamp(timestamp),self.context)

    def set_up_callback(self):
        self.callback = CALLBACK(self.callback)
        self.lib.set_callback(self.callback)

    def demo(self,context):
        self.context = context
        self.lib.demo(None)

demo = Demo()
demo.demo([1,2,3])
demo.demo(123.456)
demo.demo('a context')

Вывод:

1.5 2.4000000953674316 1.2999999523162842 2020-04-11 11:38:44 [1, 2, 3]
1.5 2.4000000953674316 1.2999999523162842 2020-04-11 11:38:44 123.456
1.5 2.4000000953674316 1.2999999523162842 2020-04-11 11:38:44 a context
...