Boost Python: 停止解释器

Boost Python: stop interpreter

在 [=34 内通过 Boost Python 调用 Python 方法后,有什么方法可以停止 运行 Python 解释器=] C++?

我想中断通话有两个原因:

  1. 如果超时期限已过(即脚本运行 "too long")。
  2. 如果另一个(并行 运行)Python 脚本失败。

我在网络和 Boost 文档中的搜索没有找到任何结果,但另一方面,我有时很难在 Boost 文档中找到正确的段落...

我唯一的"sort of idea"就是从这个Whosebug question中得到的。我的想法是向脚本发送一个信号,但是当解释器在我的 C++ 进程中运行时,这可能不是一个可行的选择?!

我正在做以下事情:

const boost::filesystem::path pythonScriptPath = /* Path to the script I want to execute a function from. */
const std::string pythonFunctionName = /* Name of the Python function to call. */;

boost::python::object mainModule = boost::python::import("__main__");
boost::python::object mainNameSpace = mainModule.attr("__dict__");

boost::python::dict locals;
locals["moduleName"] = pythonScriptPath.stem().string();
locals["modulePath"] = pythonScriptPath.string();

std::stringstream importModuleStream;
importModuleStream
    << "import imp\n"
    << "newModule = imp.load_module(moduleName, open(modulePath), modulePath, ('py', 'U', imp.PY_SOURCE))\n";

boost::python::exec(importModuleStream.str().c_str(), mainNameSpace, locals);

auto pythonScript = locals["newModule"];

auto pythonFunction = pythonScript_.attr(pythonFunctionName .c_str());
pythonFunction(/* args */);

现在的问题是:

我可以interrupt/abort pythonFunction() 触发后执行吗? 如果我调用它的方式不可能,是否有另一种方法可以使用 Boost Python 调用 Python 函数,所以我 可以 中止调用?

我 运行 在 Linux 下(以防万一这启用了一些依赖于平台的解决方案,我会非常满意)。

没有找到真正的"stop interpreter from the outside"方法。 但是 我创建了一个解决方法,至少可以在我的情况下完成工作。也许它会对其他人有所帮助...

我的想法是,我在 Python 脚本中有一个线程,它除了等待被唤醒外什么都不做。它通过从 C++ 中调用 "abort" 函数来唤醒。一旦它被唤醒,它就会从内部杀死脚本。在这个例子中我选择了一种粗略的方法来停止脚本:

os._exit(1)

确实有更好的方法可以做到这一点,但这超出了这里的重点。整个中止和终止的东西也可以包装得更好,但再一次:我只是想勾勒出这个想法。

我的测试 Python 脚本如下所示:

import threading
import time
import os

def abort():
    global run
    run = False
    global condition
    with condition:    
        condition.notify()

def threadBlock():
    while True:
        print( "Blocking!" )
        time.sleep(3)

def threadTerminate():    
    while run:
        global condition
        with condition:
            condition.wait()

    global kill
    if kill:
        os._exit(1)

def myEntryFunction()
    blockingThread = threading.Thread( target = threadBlock )
    terminatingThread = threading.Thread( target = threadTerminate )

    blockingThread.start()
    terminatingThread.start()

    threadBlock().join()
    global kill
    kill = False
    global condition
    with condition:    
        condition.notify()      
    terminatingThread.join()



run = True;
kill = True;
condition = threading.Condition()

C++ 中,我这样终止脚本:

// other code (see question)

std::thread killer([&pythonScript] () {
    std::chrono::seconds d(15);
    std::this_thread::sleep_for(d);
    AcquireGIL gil;
    pythonScript.executeFunction("abort");          
});

pythonFunction(/* args */);

AcquireGIL 看起来像这样:

#include <boost/python.hpp>

class AcquireGIL final
{
public:
    AcquireGIL();
    ~AcquireGIL();


private:
    PyGILState_STATE gilState_;
};

AcquireGIL::AcquireGIL()
: gilState_(PyGILState_Ensure()) {
    // nothing to do...
}

AcquireGIL::~AcquireGIL() {
    PyGILState_Release(gilState_);
}

编辑

不同(相似)的方法

在我的脚本的入口函数中,我启动了一个线程作为 守护进程 调用辅助函数。辅助函数调用辅助方法(执行我真正想做的事情)。 worker 方法returns 之后,助手向条件变量发出信号。主线程只是等待这个条件。如果我想从外部中止,我也只通知条件。当主线程结束时,辅助线程已经结束,或者在外部中止的情况下,将被清理。

关注

如果中止,辅助线程将无法正确清理。所以你必须处理它或手动处理它。