4

我想使用扭曲应用程序中的 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 正在产生一个线程。

我拥有的锁是否会确保回调函数在主循环l的操作中间时不会尝试访问列表pop,反之亦然?还是仅当您使用使用threading库创建的线程时,此方案才有效?这里推荐的做法是什么?

4

1 回答 1

3

ctypes 做的第一件事_CallPythonObject是 call PyGILState_Ensure(),如果需要,它会调用PyThreadState_New来创建一个新的线程状态。除此之外,它是普通的 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;
}
于 2013-04-11T19:53:26.973 回答