我正在用C++编写一个Python扩展,包装一个我无法控制的第三方库.该库创建了一个Python一无所知的线程,并从该线程调用我提供给库的C++回调.我希望该回调调用Python函数,但我使用从文档中读取的方法得到了死锁.这是我对这些的解释.
void Wrapper::myCallback()
{
PyGILState_STATE gstate=PyGILState_Ensure();
PyObject *result=PyObject_CallMethod(_pyObj,"callback",nullptr);
if (result) Py_DECREF(result);
PyGILState_Release(gstate);
}
Run Code Online (Sandbox Code Playgroud)
我的代码没有做任何与线程相关的事情,尽管我已经尝试了许多其他的东西.基于此,例如,我尝试调用PyEval_InitThreads(),但是对于扩展应该在何处进行调用并不明显.我把它放进去了PyMODINIT_FUNC.这些尝试都会导致Python死锁,崩溃或神秘的致命错误,例如PyEval_ReleaseThread:错误的线程状态.
这是在Linux上使用Python 3.6.1.任何想法如何让这个"简单"的回调工作?
我没有意识到在另一个线程中,库在忙/等待循环中等待回调的线程.在gdb,info threads使这显而易见.我能看到的唯一解决方案是跳过对回调的特定调用; 鉴于忙/等待循环,我没有看到让它们安全的方法.在这种情况下,这是可以接受的,这样做可以消除死锁.
此外,似乎我还需要PyEval_InitThreads()在此之前调用.在C++扩展中,不清楚应该去哪里.其中一个回复建议通过创建和删除一次性来间接地在Python中进行threading.Thread.这似乎没有解决它,而是触发一个致命的Python错误:take_gil:NULL tstate,我认为这意味着仍然没有GIL.我的猜测,基于这个和它引用的问题,是PyEval_InitThreads()导致当前线程成为GIL的主线程.如果在短暂的一次性线程中进行该调用,可能这是一个问题.是的,我只是在猜测,并希望得到一个没有必要的人的解释.
如何定义一个以某种方式派生自int、具有自定义起始值并添加自定义属性的 Python 枚举类?我知道如何从int使用中导出enum.IntEnum并设置起始值,
Goo = enum.IntEnum("Goo", "MOO FOO LOO", start = 42)
Run Code Online (Sandbox Code Playgroud)
以及如何将自定义属性添加到基本枚举类型,
class Goo(enum.Enum):
MOO = (42, "forty-two")
FOO = (43, "forty-three")
LOO = (44, "forty-four")
def __init__(self, value, alias):
self._value = value #self.value gives AttributeError, as expected, grrr...
self.alias = alias
Run Code Online (Sandbox Code Playgroud)
但我该如何做到这三个呢?__new__()我也尝试过各种办法
class Goo(int, enum.Enum):
MOO = (42, "forty-two")
FOO = (43, "forty-three")
LOO = (44, "forty-four")
def __new__(cls, value, alias):
self = super().__new__(cls, value)
self.alias = alias
return self …Run Code Online (Sandbox Code Playgroud)