从 C 调用 python 函数作为回调。处理 GIL 的正确方法是什么?
Calling python function from C as a callback. What is the right way to handle the GIL?
我正在使用 cytpes
来包装 C api。 api 函数之一允许您注册回调。我正在使用 CFUNCTYPE
来指定函数的类型,并从我的 python 库的用户提供的 python 函数创建 CFUNCTYPE
的实例,然后我将其传递给C 函数(使用 ctypes
api 调用)。
我知道 ctypes
调用会释放 GIL
。我想知道当 C 库函数调用我的 python 回调函数时会发生什么。 ctypes
是否重新获取 GIL
?
Note: Make sure you keep references to CFUNCTYPE()
objects as long as they are used from C code. ctypes
doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made.
Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback), ctypes
creates a new dummy Python thread on every invocation. This behavior is correct for most purposes, but it means that values stored with threading.local
will not survive across different callbacks, even when those calls are made from the same C thread.
它没有提到 GIL
。这是否意味着它都为我处理了?
CThunkObject
referenced in the callback's _objects
attribute has the pcl_exec
function pointer that the C library calls. This code calls closure_fcn
with a reference to the thunk, plus the call args
and a pointer to memory to store the result. The closure function in turn calls _CallPythonObject
, with the thunk's restype
, setfunc
, callable
, converters
, and flags
as parameters. The first thing _CallPythonObject
does is call PyGILState_Ensure
获取GIL。即使这是 Python 第一次看到当前线程,这仍然有效。
也就是说,都给你搞定了。只需保留对回调的引用以保持对 thunk 的引用。
我正在使用 cytpes
来包装 C api。 api 函数之一允许您注册回调。我正在使用 CFUNCTYPE
来指定函数的类型,并从我的 python 库的用户提供的 python 函数创建 CFUNCTYPE
的实例,然后我将其传递给C 函数(使用 ctypes
api 调用)。
我知道 ctypes
调用会释放 GIL
。我想知道当 C 库函数调用我的 python 回调函数时会发生什么。 ctypes
是否重新获取 GIL
?
Note: Make sure you keep references to
CFUNCTYPE()
objects as long as they are used from C code.ctypes
doesn’t, and if you don’t, they may be garbage collected, crashing your program when a callback is made. Also, note that if the callback function is called in a thread created outside of Python’s control (e.g. by the foreign code that calls the callback),ctypes
creates a new dummy Python thread on every invocation. This behavior is correct for most purposes, but it means that values stored withthreading.local
will not survive across different callbacks, even when those calls are made from the same C thread.
它没有提到 GIL
。这是否意味着它都为我处理了?
CThunkObject
referenced in the callback's _objects
attribute has the pcl_exec
function pointer that the C library calls. This code calls closure_fcn
with a reference to the thunk, plus the call args
and a pointer to memory to store the result. The closure function in turn calls _CallPythonObject
, with the thunk's restype
, setfunc
, callable
, converters
, and flags
as parameters. The first thing _CallPythonObject
does is call PyGILState_Ensure
获取GIL。即使这是 Python 第一次看到当前线程,这仍然有效。
也就是说,都给你搞定了。只需保留对回调的引用以保持对 thunk 的引用。