簡體   English   中英

Python Ctypes注冊回調函數

[英]Python Ctypes register callback functions

我使用Python和ctypes遇到了非常奇怪的事情。 我正在使用Python 3.4.3。 首先,項目的一些背景:

我已經從C代碼編譯了一個自定義dll。 我正在使用ctypes與dll進行接口。 C庫與某些自定義硬件連接。 有時,硬件會生成一個中斷,並將其傳遞給計算機上的C庫。 在C API中,有一個帶有原型void register_callback(int addr, void (*callback)(void))的函數。 我有一個回調函數指針數組,它們初始化為NULL。 調用此函數時,索引addr處的回調函數指針將設置為callback,如下所示: callbacks[addr] = callback;

當用戶使用Python進行編程時,他們從對不同硬件部件(例如按鈕或RGB LED)建模的類中實例化對象。 然后,他們可以編寫一個自定義的回調函數並調用button.register_callback(func) (假設他們有一個名為button的Button對象),該對象將在C庫中調用register_callback函數。 現在,當按下按鈕並生成中斷時,C庫將調用適當的回調函數(即callbacks[addr](); )。

現在,奇怪的是:

在Python中,我第一次嘗試使用Python中的register_callback方法如下:

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

而在主要方面:

def cb1():
    print("cb1")

def cb2():
    print("cb2")

def main(argv):
    # Initialization stuff
    # Now create the objects and register the callbacks:
    obj = Obj_module.Obj()
    obj2 = Obj_module.Obj()
    obj.register_callback(cb1)
    obj2.register_callback(cb2)

    while True:
        pass

當我運行此命令時,無論我按下哪個按鈕,都僅打印“ cb2”。 真正奇怪的是,當我切換注冊回調的順序時:

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

無論我按下哪個按鈕,都僅打印“ cb1”! 在C庫中,我(通過printf驗證)根據按鈕的不同,正在設置和調用不同的回調函數指針,但已將同一函數指針傳遞給C register_callback函數。

我能夠通過在register_callback方法中添加一行來解決此問題:

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 POINTER可以解決此問題-傳入了不同的函數指針,並且我成功地看到了打印的“ cb1”或“ cb2”,具體取決於我按下的按鈕。

我的問題是,為什么? 為什么在原始代碼中傳遞了相同的函數指針,為什么根據我注冊回調的順序進行了更改,為什么將cb_ptr轉換為ctypes POINTER才能確保函數指針不同?

我是Python的初學者,但我在C方面經驗豐富。預先感謝您的回復。

您的cb_ptr正在被垃圾回收。 文檔中

確保保留對CFUNCTYPE()對象的引用,只要它們是從C代碼中使用的即可。 ctypes不會,如果您不這樣做,則可能會被垃圾回收,從而使您的程序在進行回調時崩潰。

在此代碼示例中,如果注釋掉了ptrs.append(cb_ptr)行,則兩個Obj實例的cb_ptr位置都相同(在我的計算機上)。 取消注釋該行將導致兩個存儲位置。

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM