首页 > 解决方案 > 如何为在 C++ 应用程序中使用嵌入 python 创建的新线程状态获取 GIL

问题描述

我有一个 C++ 应用程序,我们提供了一个 python 编辑器(使用 python 3.7),用户可以在编辑器中输入和执行 python 代码。以下是我们在执行用户提供的脚本之前创建新线程状态并使其成为当前状态的示例代码。

#include <python.h>

PyThreadState* globalthread;

void executescript()
{
    PyEval_SaveThread();
    PyThreadState* ts = PyThreadState_New(globalthread->interp);
    int gilstate = PyGILState_Check(); //check whether GIL is with current thread or not
    if (!gilstate)
    {
        PyEval_RestoreThread(ts);
    }
    else
    {
        
        PyThreadState_Swap(ts);
    }
    // get the thread state with which GIL is currently assigned
    PyThreadState * gilthreadstate = PyGILState_GetThisThreadState(); 
    //----> the above line return pointer to global thread state (gilthreadstate == globalthread)
    //----> which means the GIL is not acquired by the new current thread
    gilstate = PyGILState_Check(); //results in zero as GIL is not with current thread
    std::string str = "def script():\n\timport sys\n\tsys.path.append('C:\\Python\\Python37\\Lib\\site-packages')\n\tprint(sys.path)\n\timport numpy\n\tarr = numpy.array([1, 2, 3, 4, 5])\n\tprint(arr)\nscript()";
    PyRun_SimpleString(str.c_str());
    PyThreadState_Clear(ts);
    PyThreadState_DeleteCurrent();
    PyEval_RestoreThread(globalthread);
    //following stmt returns 1 as the current thread is global thread and it has GIL with it
    gilstate = PyGILState_Check(); 
}

int main()
{
    Py_Initialize();
    PyEval_InitThreads();
    globalthread = PyThreadState_Get();
    executescript();
    PyThreadState_Swap(globalthread);
    Py_FinalizeEx();
    return 0;
} 

新的当前线程在调用 PyEval_RestoreThread 或 PyThreadState_Swap 时未获取 GIL。由于这个原因,Python 脚本已经import numpy或将会以死锁告终。import pandas有人可以让我知道如何获取新线程状态的 GIL 或代码错误的地方吗?

标签: pythonc++python-3.xnumpypython-c-api

解决方案


hn-1-8e9-wheres-my-share-m 的评论通过创建一个新的 C++ 线程解决了这个问题。这是我修改后的代码。

#include <python.h>
#include <thread>
PyThreadState* globalthread;

void execute()
{
    PyThreadState* ts = PyThreadState_New(globalthread->interp);

    int gilstate = PyGILState_Check();
    if (!gilstate)
    {
        PyEval_RestoreThread(ts);
    }
    else
    {

        PyThreadState_Swap(ts);
    }
    std::string str = "def script():\n\timport sys\n\tsys.path.append('C:\\Python\\Python37\\Lib\\site-packages')\n\tprint(sys.path)\n\timport numpy\n\tarr = numpy.array([1, 2, 3, 4, 5])\n\tprint(arr)\nscript()";
    PyRun_SimpleString(str.c_str());
    PyThreadState_Clear(ts);
    PyThreadState_DeleteCurrent();
}

int main()
{
    Py_Initialize();
    globalthread = PyThreadState_Get();
    PyEval_SaveThread();
    std::thread t(executePythonScript);
    t.join();
    PyEval_RestoreThread(globalthread);
    //PyThreadState_Swap(globalthread);
    Py_FinalizeEx();
    return 0;
}

感谢您指出帖子。


推荐阅读