为什么在两个线程内中继和获取GIL会导致应用程序崩溃?

2024-04-26 17:37:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我用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吗?有没有可能导致僵局的情况?在


Tags: 方法pysaveexception线程pyobjectstdtry
1条回答
网友
1楼 · 发布于 2024-04-26 17:37:51

What is the root reason of this problem and how should I fix it?

问题的根本原因是,如果在两个线程中运行DoComputation1(),并且此方法引发异常,则两个线程都将运行catch块。在catch块中,使用了一些Python API函数。因此,这意味着Python实现中确实存在两个线程,这将导致崩溃。在

If I bring the PyEval_RestoreThread(_save); line (in the catch block) to the beginning of the catch block, no crash happends. Does it mean that during the time that GIL is released, I should not call any Python API?

如果将PyEval_RestoreThread(_save);行放在catch块的第一行,这意味着catch块内的代码将由两个线程按顺序执行。所以,没有发生车祸。在

Should I lock my mutex before releaseing the GIL of after that?

我认为最好同时使用std::lock(...)之类的构造将它们锁定在一起。但为此,首先需要GIL的包装类使其成为lockable对象。在

Is there any case that may lead to a deadlock?

如果两者(GIL release和mutex lock)按建议结合在一起,我不认为会发生死锁。在

相关问题 更多 >