В общем стоит задача встроить Python 3.2 в легковесное многопотоковое C++ приложение (Boost::python сразу лесом, жирный он больно), используя Cython API. При попытке одновременного запуска 2х PyEval_EvalCode с жирными скриптами в разных потоках получаем «ceval: tstate mix-up», короче падаем тут:
//Python 3.2.2 source
//ceval.c, line 1321
#ifdef WITH_THREAD
if (_Py_atomic_load_relaxed(&gil_drop_request)) {
/* Give another thread a chance */
if (PyThreadState_Swap(NULL) != tstate)
Py_FatalError("ceval: tstate mix-up");
drop_gil(tstate);
/* Other threads may run now */
take_gil(tstate);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");
}
#endif
Инициализация питона:
// Init Python
const char *version = Py_GetVersion();
if (version) {
logMsg.msg("Python version %s\n", version);
}
else {
logMsg.error("Error get Python version!\n");
}
PyImport_ExtendInittab(ScriptModule::builtin_modules);
Py_SetProgramName(L"Python");
if (!Py_IsInitialized()) {
Py_InitializeEx(0);
}
PyEval_InitThreads();
m_mainThreadState = PyThreadState_Get();
PyThreadState *tstate = PyEval_SaveThread();
PyGILState_STATE gstate = PyGILState_Ensure();
const wchar_t* arg0 = L"";
PySys_SetArgv(0, const_cast<wchar_t**>(&arg0));
PyGILState_Release(gstate);
m_globaldict = gcreateGlobalDict();
Создание нового потока:
if (pthread_create(&m_thread, 0, thread_run, this)) {
ASSERT_T(!"Cannot create thread");
}
Функция thread_run запускает в своем теле метод run():
PyObject *py_res=NULL;
PyGILState_STATE py_gilstate;
ASSERT_T(m_text->compiled);
ASSERT_T(m_globaldict);
//При запуске второго потока падаем с
//описанной выше ошибкой здесь:
py_gilstate = PyGILState_Ensure();
m_pyThreadState = PyThreadState_Get();
logMsg.msg("start execute\n");
py_res = PyEval_EvalCode( (PyObject*)m_text->compiled, m_globaldict, m_globaldict );
if( !py_res ) {
logMsg.error("Error run script!\n");
}
else {
Py_DecRef(py_res);
logMsg.msg("python code executed\n");
}
PyGILState_Release(py_gilstate);
logMsg.msg("end execute\n");
PyEval_EvalCode имеют общий globaldict.
Пример питоноского скрипта-лупа (при запуске его и любого 2ого скрпита падаем):
while (1==1):
//do somthing
Не совсем понятно, почему PyGILState_Ensure() в другом потоке вываливается с ошибкой указанной выше. Пока проблему решил, добавив мютекс в метод run(), но меня это не устраивает, поскольку нужна одновременная работа 2х скриптов в PyEval_EvalCode.