簡體   English   中英

在ctypes回調函數中使用線程鎖

[英]Using threading lock in ctypes callback function

我想從扭曲的應用程序中使用ctypes dll。 最小的例子在這里炮制:

from ctypes import *
from threading import Lock

lock = Lock()

dll = windll.LoadLibrary('mydll.dll')

l = [1,2,3]

def callback():
    lock.acquire()
    l.pop()
    lock.release()
    return 0

C_CALLBACK = CFUNCTYPE(c_int)
c_callback = C_CALLBACK(callback)

# this is a non blocking function call starts a hardware task that fires a callback upon completion
dll.registerCallback(c_callback)

while(True):
    # in reality this block gets called from a twisted server application
    lock.acquire()
    l.append(l.pop() + 1)
    lock.release()

dll有一個函數( dll.registerCallback ),它接受ctypes回調函數,啟動硬件事件,並在硬件指示硬件任務完成時觸發回調。

從API文檔:

回調函數在DAQmx線程中調用。

在網絡上的某個地方,他們試圖解釋“DAQmx線程”是什么:

...您的回調將在DAQmx驅動程序線程中調用並運行,並且將與您的程序異步運行(不在同一個線程中)。

完整的文檔可以在這里找到。 為簡單起見,我在我的示例中更改了函數簽名。

所以我想我們可以安全地假設dll正在產生一個線程。

我現有的鎖是否確保回調函數在主循環中pop操作的中間時不會嘗試訪問列表l ,反之亦然? 或者,此方案僅在使用使用threading庫創建的threading時才有效? 這里的推薦做法是什么?

ctypes _CallPythonObject做的第一件事是調用PyGILState_Ensure() ,如果需要,它將調用PyThreadState_New來創建一個新的線程狀態。 除此之外,它是vanilla Python線程代碼,所以你的鎖應該可以正常工作。 它在下面的示例中適用於我(Linux,Python 2.7.3):

from ctypes import *
import threading

lock = threading.Lock()
lib = CDLL('./tmp.so')
callback_t = CFUNCTYPE(c_int)

def f():
  with lock:
    print threading.current_thread()
  return 21

callback = callback_t(f)
lib.registerCallback(callback)
>>> lock.acquire()
True
>>> t = threading.Thread(target=lib.event)
>>> t.start()
>>> lock.locked()
True
>>> lock.release()
>>> <_DummyThread(Dummy-2, started daemon -1230402704)>
res: 21

DummyThread輸出來自打印回調中的當前線程。 在Python之外創建的線程獲得一個“虛擬”名稱。

tmp.c:

#include <stdio.h>
#include <pthread.h>

typedef int (*callback_t)(void);
callback_t callback = NULL;

void *doCallback(void *arg)
{
    int res = callback();
    printf("res: %d\n", res);
    pthread_exit(0);
}

int event(void)
{
    pthread_t callback_thread;
    pthread_create(&callback_thread, NULL, doCallback, NULL);
    pthread_join(callback_thread, NULL);
    return 0;
}

int registerCallback(callback_t foo)
{
    callback = foo;
    return 0;
}

暫無
暫無

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

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