擅长:python、mysql、java
<p>阿巴内特的回答提供了正确的函数,但是这个解释让我很困扰,所以我很早就回到家里,又找了一些。在</p>
<p>在开始解释之前,我想指出,当我说GIL时,我严格地说的是互斥体、信号量或全局解释器锁用来进行线程同步的任何东西。这不包括Python在获取和发布GIL之前/之后所做的任何其他内务处理。在</p>
<p>单线程程序不会初始化GIL,因为您从不调用PyEval_InitThreads()。因此没有GIL。即使发生了锁定,这也不重要,因为它是单线程的。然而,获取和释放GIL的函数除了获取/释放GIL之外,还会做一些有趣的事情,比如扰乱线程状态。关于WINFUNCTYPE对象的文档明确指出,它在跳转到C之前释放GIL。因此,当在Python中调用C回调时,我怀疑调用了PyEval_SaveThread()之类的东西(可能是错误的,因为至少据我的理解,它只在线程操作中被调用)。这将释放GIL(如果存在的话)并将线程状态设置为NULL,但是在单线程Python程序中没有GIL,因此它真正做的只是将线程状态设置为NULL。这会导致C回调中的大多数Python函数失败。在</p>
<p>实际上,调用PyGILState_sure/Release的唯一好处是告诉Python在运行和执行操作之前将线程状态设置为有效的状态。没有要获取的GIL(未初始化,因为我从未调用PyEval_InitThreads())。在</p>
<p>为了测试我的理论:在main函数中,我使用PyThreadState_Swap(NULL)来获取线程状态对象的副本。我在回调过程中恢复它,一切正常。如果我将线程状态保持为null,那么即使不执行Python->;C回调,也会出现几乎相同的访问冲突。在cfunc1中,我恢复了线程状态,并且在Python->;C回调期间,cfunc1本身不再有问题。在</p>
<p>cfunc1返回Python代码时会出现问题,但这可能是因为我搞乱了线程状态,而WINFUNCTYPE对象期望的是完全不同的东西。如果您保持线程的状态,而在返回时没有将其设置回null,那么Python只会坐在那里不做任何事情。如果你把它恢复为null,它就会崩溃。但是,它确实成功地执行了cfunc1,所以我不确定我是否太在意。在</p>
<p>我可能最终会在Python源代码中找到100%的确定,但我确信足够满意。在</p>