PyThreadState\u SetAsyncExc具有n

2024-04-25 01:39:47 发布

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

我使用多线程的多解释器,并尝试使用PyThreadState_SetAsyncExc来停止脚本,但没有效果:

void stop()
{
    PyThreadState *ts = PyThreadState_Swap(this->tstate);
    PyObject *exc = PyObject_CallObject(PyExc_Exception, Py_BuildValue("(s)", "stopped"));
    int n = PyThreadState_SetAsyncExc(this->tstate->thread_id, exc);
    if(n < 1)
        std::cerr << "Script::stop: thread not found!" << std::endl;
    PyThreadState_Swap(ts);
}

返回值为1,但线程继续运行。为什么

完整测试用例:

#include <Python.h>
#include <iostream>
#include <thread>

using namespace std::chrono_literals;

struct Script
{
    Script()
    {
        PyThreadState *ts = PyThreadState_Get();
        this->tstate = Py_NewInterpreter();
        PyThreadState_Swap(ts);
    }

    virtual ~Script()
    {
        if(!this->tstate) return;
        PyThreadState *ts = PyThreadState_Swap(this->tstate);
        Py_EndInterpreter(this->tstate);
        PyThreadState_Swap(ts);
    }

    void run(const char *code)
    {
        PyThreadState *ts = PyThreadState_Swap(this->tstate);
        PyRun_SimpleStringFlags(code, nullptr);
        PyThreadState_Swap(ts);
    }

    void run_thread(const char *code)
    {
        thread = std::thread{std::bind(&Script::thread_func, this, code)};
    }

    void join()
    {
        thread.join();
    }

    void stop()
    {
        PyThreadState *ts = PyThreadState_Swap(this->tstate);
        PyObject *exc = PyObject_CallObject(PyExc_Exception, Py_BuildValue("(s)", "stopped"));
        int n = PyThreadState_SetAsyncExc(this->tstate->thread_id, exc);
        if(n < 1)
            std::cerr << "Script::stop: thread not found!" << std::endl;
        PyThreadState_Swap(ts);
    }

private:
    void thread_func(const char *code)
    {
        PyThreadState *ts = PyThreadState_New(this->tstate->interp);
        PyEval_RestoreThread(ts);
        PyThreadState *ts0 = PyThreadState_Swap(ts);
        PyRun_SimpleStringFlags(code, nullptr);
        PyThreadState_Swap(ts0);
        PyThreadState_Clear(ts);
        PyThreadState_DeleteCurrent();
    }

    PyThreadState *tstate;
    std::thread thread;
};

int main(int argc, char *argv[])
{
    Py_InitializeEx(1);
    PyEval_InitThreads(); // implicit since python 3.7

    Script s1, s2;
    s1.run_thread(
R"PY(
import time
import sys
i = 0
while 1:
    i += 1
    time.sleep(1)
    sys.stdout.write('s1: %d\n' % i); sys.stdout.flush()
)PY");

    PyThreadState *ts = PyEval_SaveThread();
    std::this_thread::sleep_for(4s);
    std::cout << "trying to stop s1..." << std::endl;
    s1.stop();
    s1.join();
    PyEval_RestoreThread(ts);

    PyMem_RawFree(program);

    if (Py_FinalizeEx() < 0)
        return 120;
    return 0;
}

Tags: pyscriptcodethisthreadexcpyobjectstd