从C调用python函数作为回调。处理GIL的正确方法是什么?

时间:2016-01-08 21:58:44

标签: python callback ctypes gil

我使用cytpes打包C api。其中一个api函数允许您注册回调。我使用CFUNCTYPE来指定函数的类型,并从我的python库的用户提供的python函数中创建CFUNCTYPE的实例,然后将其传递给C函数(使用ctypes api调用)。

我知道ctypes次调用会释放GIL。我想知道当C库函数调用我的python回调函数时会发生什么。 ctypes是否重新获取GIL

documentation说:

  

注意:确保只要从C代码中使用CFUNCTYPE()个对象,就会保留对它们的引用。 ctypes没有,如果你不这样做,它们可能会被垃圾收集,在回调时会崩溃你的程序。   另请注意,如果在Python控件之外创建的线程中调用回调函数(例如,通过调用回调的外部代码),ctypes会在每次调用时创建一个新的虚拟Python线程。对于大多数用途,此行为是正确的,但这意味着与threading.local一起存储的值将无法在不同的回调中存活,即使这些调用是从同一个C线程进行的。

它没有对GIL说些什么。这是否意味着它全部都是为我处理的?

1 个答案:

答案 0 :(得分:4)

回调的_objects属性中引用的CThunkObject具有C库调用的pcl_exec函数指针。此代码使用对thunk的引用调用closure_fcn,加上调用args和指向存储结果的内存的指针。闭包函数依次调用_CallPythonObject,将thunk的restypesetfunccallableconvertersflags作为参数。 _CallPythonObject做的第一件事是调用PyGILState_Ensure来获取GIL。这是有效的,即使这是Python第一次看到当前的线程。

换句话说,这一切都是为你处理的。只需保留对回调的引用,以保持引用的thunk。