LINUX.ORG.RU

Cython и одновременное выполнение PyEval_EvalCode в разных потоках

 , py3


0

1

В общем стоит задача встроить 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.

Код не смотрел, но в питоне только один тред может быть активным. Выставлять и высвобождать GIL надо явно. В доках и в инете куча примеров на эту тему.

Единственные треды которые могут работать паралельно это те что не обращаются к внутренностям питона.

true_admin ★★★★★
()

Всем спс, проблему решил. Код что выше, правильный, косяк был в освобождении globaldict перед запуском 2ого скрипта, из-за чего первый скрипт оставался некоторое время без словаря.

ApostolPetr
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.