首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在多线程C应用程序中嵌入python

在多线程C应用程序中嵌入python
EN

Stack Overflow用户
提问于 2012-05-17 03:43:58
回答 4查看 7.1K关注 0票数 18

我将python解释器嵌入到一个多线程的C应用程序中,对于应该使用什么API来确保线程安全,我感到有点困惑。

据我所知,在嵌入python时,在调用任何其他Python C API调用之前,需要由嵌入器来处理GIL锁。这是通过以下函数完成的:

代码语言:javascript
复制
gstate = PyGILState_Ensure();
// do some python api calls, run python scripts
PyGILState_Release(gstate);

但仅有这一点似乎还不够。我仍然会遇到随机崩溃,因为它似乎没有为Python API提供互斥。

在阅读了更多的文档后,我还补充道:

代码语言:javascript
复制
PyEval_InitThreads();

就在调用Py_IsInitialized()之后,但这就是令人困惑的部分。文档中提到了这个函数:

初始化并获取全局解释器锁

这表明当此函数返回时,GIL应该是锁定的,并且应该以某种方式解锁。但在实践中,这似乎不是必需的。有了这行代码,我的多线程就可以很好地工作,并且PyGILState_Ensure/Release函数可以维护互斥。

当我尝试在PyEval_ReleaseLock()之后添加PyEval_ReleaseLock()时,应用程序在随后的PyImport_ExecCodeModule()调用中很快就死锁了。

那么我在这里错过了什么呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-05-22 20:33:11

最终我发现了这一点。

之后

代码语言:javascript
复制
PyEval_InitThreads();

你需要打电话给

代码语言:javascript
复制
PyEval_SaveThread();

同时适当地释放主线程的GIL。

票数 4
EN

Stack Overflow用户

发布于 2014-01-26 23:56:23

我遇到了完全相同的问题,现在可以按照您上面的建议,在PyEval_InitThreads()之后立即使用PyEval_SaveThread()来解决这个问题。然而,我的实际问题是,我在PyInitialise()之后使用PyEval_InitThreads(),这会导致PyGILState_Ensure()在从不同的后续本机线程调用时阻塞。总而言之,这是我现在要做的:

  1. 有一个全局变量:

static int = 0;

  • 从主线程加载本地C扩展并启动Python解释器:

Py_Initialize()

  • 从多个其他线程我的应用程序并发地对Python/C应用程序接口进行了大量调用:

如果(! gil_init ) {gil_init= 1;PyEval_InitThreads();PyEval_SaveThread();}状态= PyGILState_Ensure();//调用Python/C API函数...PyGILState_Release(state);

  • From主线程停止Python解释器

Py_Finalize()

我尝试过的所有其他解决方案要么会导致随机的Python信号错误,要么会使用PyGILState_Ensure()导致死锁/阻塞。

Python文档确实应该更清楚地说明这一点,并至少为嵌入和扩展用例提供一个示例。

票数 8
EN

Stack Overflow用户

发布于 2022-01-22 18:16:57

注意,@forman的答案中的if (!gil_init) {代码只运行一次,所以它可以在主线程中很好地完成,这允许我们删除标志(gil_init应该是原子的或以其他方式同步的)。

PyEval_InitThreads()只有在CPython 3.6和更早的版本中才有意义,并且在CPython 3.9中已被弃用,因此必须用宏保护它。

考虑到所有这些,我目前使用的是:

在主线程中,运行

代码语言:javascript
复制
Py_Initialize();
PyEval_InitThreads(); // only on Python 3.6 or older!
/* tstate = */ PyEval_SaveThread(); // maybe save the return value if you need it later

现在,无论何时需要调用Python,都可以

代码语言:javascript
复制
state = PyGILState_Ensure();
// Call Python/C API functions...    
PyGILState_Release(state);

最后,从主线程停止Python解释器

代码语言:javascript
复制
PyGILState_Ensure(); // PyEval_RestoreThread(tstate); seems to work just as well
Py_Finalize()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10625584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档