Python Ctypes注册回调函数

2024-09-24 08:34:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用Python和ctypes时遇到了一些非常奇怪的问题。我使用的是python3.4.3。首先,项目背景:

我用C代码编译了一个自定义dll。我正在使用ctypes与dll接口。C库正在与一些自定义硬件接口。有时,硬件会生成一个中断并将其传递给计算机上的C库。在C API中,有一个原型为void register_callback(int addr, void (*callback)(void))的函数。我有一个回调函数指针数组,它们被初始化为NULL。调用此函数时,index addr处的回调函数指针设置为callback,如下所示:callbacks[addr] = callback;。在

当用户用Python编写程序时,它们会从对不同硬件部件(如按钮或RGB-LED)建模的类中实例化对象。然后,他们可以编写一个自定义回调函数并调用button.register_callback(func)(当然,假设他们有一个名为Button的按钮对象),该对象调用C库中的register_回调函数。现在,当按下按钮并生成中断时,C库将调用适当的回调函数(即callbacks[addr]();)。在

现在,奇怪的是:

在Python中,我第一次尝试在Python中使用register_回调方法,如下所示:

class Obj:
    def __init__(self, name):
        # Initialize stuff

    def register_callback(self, func):
        CB_T = ctypes.CFUNCTYPE(None)
        cb_ptr = CB_T(func)
        host_api.register_callback(self.addr, cb_ptr) # host_api is the loaded dll

主要是:

^{pr2}$

当我运行这个,只有“cb2”被打印,不管我按哪个按钮。真正奇怪的是,当我改变注册回调的顺序时:

    obj2.register_callback(cb2)
    obj.register_callback(cb1)

不管我按了什么按钮,只有“cb1”正在打印!在C库中,我(通过printf)验证了根据按钮设置和调用了不同的回调函数指针,但是相同的函数指针被传递给C register_回调函数。在

我通过在register\u回调方法中添加一行来解决这个问题:

def register_callback(self, func):
    CB_T = ctypes.CFUNCTYPE(None)
    cb_ptr = CB_T(func)
    (ctypes.cast(cb_ptr, ctypes.POINTER(ctypes.c_int)))
    host_api.register_callback(self.addr, cb_ptr)

显然,将cb ptr转换为ctypes指针修复了这个问题——不同的函数指针被传入,我成功地看到“cb1”或“cb2”被打印出来,这取决于我按下的按钮。在

我的问题是,为什么?为什么在转换原函数的时候,调用函数的顺序不同呢?为什么我要改变调用函数的顺序呢?在

我对Python有点初学者,但在C语言方面我更有经验。提前感谢您的回复。在


Tags: 函数selfregister硬件callbackctypes按钮addr
1条回答
网友
1楼 · 发布于 2024-09-24 08:34:00

您的cb_ptr正在被垃圾回收。从documentation

Make sure you keep references to CFUNCTYPE() objects as long as they are used from C code. ctypes doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.

在这个代码示例中,如果行ptrs.append(cb_ptr)被注释掉,cb_ptr的位置对于两个Obj实例是相同的(在我的计算机上)。取消注释该行将导致两个内存位置。在

import ctypes

ptrs = []

class Obj:
    def __init__(self):
        pass

    def register_callback(self, func):
        CB_T = ctypes.CFUNCTYPE(None)
        cb_ptr = CB_T(func)
        ptrs.append(cb_ptr)
        print(cb_ptr)

def cb1(): print("cb1")

def cb2(): print("cb2")

def main(argv):
    obj = Obj()
    obj2 = Obj()
    obj.register_callback(cb1)
    obj2.register_callback(cb2)

main(None)

相关问题 更多 >