在ctypes回调函数中使用线程锁 [英] Using threading lock in ctypes callback function

查看:239
本文介绍了在ctypes回调函数中使用线程锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用ctypes dll从一个扭曲的应用程序。最小示例在这里调整:

I want to use a ctypes dll from a twisted application. Minimal example concocted here:

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回调函数,启动硬件事件,并在硬件指示硬件任务完成时触发回调。

The dll has a function (dll.registerCallback) that takes in a ctypes callback function, starts a hardware event, and fires a callback when the hardware indicates the hardware task is complete.

从API文档:


在DAQmx线程中调用回调函数。

The callback function is called in a DAQmx thread.

在网络上的某个地方,他们试图解释一个DAQmx线程是什么:

Somewhere on the web they attempt to explain what a "DAQmx thread" is:


...您的回调将被调用并在DAQmx驱动程序线程中运行,并且将与您的程序异步运行(不在同一个线程中)。

...your callback will be called and run in a DAQmx driver thread and will be run asynchronously (not in the same thread) in relation to your program.

可以找到完整的文档资料这里。为了简单起见,我在示例中更改了函数签名。

The full documentation cound be found here. I changed the function signature in my example for simplicity.

所以我想我们可以放心地假设dll是一个线程。

So I suppose we can safely assume that the dll is spawning a thread.

当我在<$ c $>中放置的锁定时,确保回调函数不会尝试访问列表 l c> pop 在mainloop中操作,反之亦然吗?或者这个方案只在你使用使用 threading 库创建的线程时工作吗?这里推荐的做法是什么?

Will the locks I have in place ensure that the callback function does not attempt to access the list l when it's in the middle of the pop operation in the mainloop, and vice versa? Or does this scheme only work when you use threads created using the threading library? What is the recommended practice here?

推荐答案

ctypes的第一件事 _CallPythonObject 调用 PyGILState_Ensure() ,如果需要,它将调用 PyThreadState_New 创建一个新的线程状态。除此之外,它是香草Python线程代码,所以你的锁应该工作正常。它在我下面的例子(Linux,Python 2.7.3)工作:

The first thing that ctypes _CallPythonObject does is call PyGILState_Ensure(), which will call PyThreadState_New to create a new thread state if necessary. Beyond that it's vanilla Python threaded code, so your lock should work fine. It worked for me in the example below (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外部创建的线程会创建一个虚拟名称。

The DummyThread output is from printing the current thread in the callback. Threads created outside of Python get a 'dummy' name.

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;
}

这篇关于在ctypes回调函数中使用线程锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆