我用C++开发了Python扩展。此模块的唯一功能如下:
static PyObject *TestModule_API1(PyObject *self, PyObject *args)
{
PyThreadState *_save;
_save = PyEval_SaveThread();
try
{
DoComputation1();
PyEval_RestoreThread(_save);
}
catch (const std::exception & e)
{
PyObject * py_exception = PyErr_NewException((char*)"pyhms.error", nullptr, nullptr);
PyErr_SetString(py_exception, e.what());
PyEval_RestoreThread(_save);
return nullptr;
}
Py_RETURN_NONE;
}
每当我用两个Python线程调用这个方法时,如果DoComputation1()
方法抛出异常,应用程序就会崩溃。即使将整个try块放在std::mutex(在块的开头加锁,在块的末尾解锁)也不能解决问题。这个问题的根本原因是什么?我应该如何解决它?在
我正在使用VisualStudio2013和Python2.7在Windows10上开发。在
编辑1:
如果我把PyEval_RestoreThread(_save);
行(在catch块中)放到catch块的开头,就不会发生崩溃。这是否意味着在GIL发布期间,我不应该调用任何pythonapi?在
编辑2:
我还需要保护我的API1方法不受使用互斥体的并发线程的影响。我应该在释放GIL之前锁上我的mutex吗?有没有可能导致僵局的情况?在
问题的根本原因是,如果在两个线程中运行
DoComputation1()
,并且此方法引发异常,则两个线程都将运行catch块。在catch块中,使用了一些Python API函数。因此,这意味着Python实现中确实存在两个线程,这将导致崩溃。在如果将
PyEval_RestoreThread(_save);
行放在catch块的第一行,这意味着catch块内的代码将由两个线程按顺序执行。所以,没有发生车祸。在我认为最好同时使用
std::lock(...)
之类的构造将它们锁定在一起。但为此,首先需要GIL的包装类使其成为lockable对象。在如果两者(GIL release和mutex lock)按建议结合在一起,我不认为会发生死锁。在
相关问题 更多 >
编程相关推荐