Python 嵌入线程 -- 如何避免死锁?
有没有办法把Python嵌入到C++中,让Python能回调到C++,同时允许Python代码创建线程,并且避免死锁呢?
问题是这样的:
要调用Python,我需要持有全局解释器锁(GIL)。通常,我在第一次创建解释器时获取主线程的状态,然后使用PyEval_RestoreThread()来获取GIL,并在调用Python之前切换线程状态。
当从Python调用时,我可能需要访问一些受保护的资源,这些资源在我的主机中被一个单独的关键区域保护。这意味着Python会持有GIL(可能是从我最初调用的其他线程),然后尝试获取我的保护锁。
在调用Python时,我可能需要持有相同的锁,因为我可能正在遍历一些对象集合。
问题在于,即使我在调用Python时持有GIL,Python也可能会放弃它,把它交给另一个线程,然后让那个线程调用我的主机,期望能够获取主机的锁。与此同时,主机可能会获取主机的锁和GIL锁,然后再调用Python。这就导致了死锁。
这里的问题是,Python在我调用它的时候把GIL交给了另一个线程。这是它应该做的,但这使得锁的顺序变得不可能——即使我先获取GIL,然后获取我自己的锁,再调用Python,Python还是会从另一个线程调用我的系统,期望获取我自己的锁(因为它释放了GIL,导致顺序混乱)。
我无法让我的系统中的所有可能锁都使用GIL——而且这样也不一定有效,因为Python可能仍然会把GIL释放给另一个线程。
我也无法保证在进入Python时我的主机不持有任何锁,因为我无法控制主机中的所有代码。
所以,这是不是意味着这件事根本无法做到呢?
3 个回答
最近在pyopenssl的讨论组里,有人提到过一个类似的问题。我怕如果我尝试解释的话会说错,所以我就直接给你一个链接,你可以去看看这个具体的问题。
“当我调用Python的时候,我可能需要保持相同的锁,因为我可能正在遍历一些对象的集合。”
这通常说明一个进程里有多个线程可能不太合适。也许在这种情况下,使用多个进程,每个进程处理集合中的一个特定对象,会更合理。
独立的进程,每个进程都有自己的一组线程,可能会更容易管理。
在Python中,运行的代码应该在获取任何锁之前先释放全局解释器锁(GIL)。这样做的话,我认为就不会出现死锁的情况。