在执行boost :: python模块时在python控制台中工作

时间:2013-06-28 10:59:36

标签: python multithreading boost console boost-python

如何在从boost :: python模块执行进程时继续使用控制台?我想我必须使用线程,但我想我错过了一些东西。

import pk #my boost::python module from c++
import threading
t = threading.Thread(target=pk.showExample, args=())
t.start() 

执行showExample,它运行一个Window渲染3D内容。现在我想在此窗口运行时继续在python控制台中进行编码。上面的示例用于显示Window但无法使控制台保持交互。任何想法怎么做?感谢您的任何建议。

问候 克里斯

编辑:我也尝试在showExample()C ++代码中创建Threads,但也没有用。我可能必须让控制台成为一个线程,但我不知道如何找到任何有用的示例。

Edit2:为了使示例更简单,我实现了这些c ++方法:

void Example::simpleWindow()
{
    int running = GL_TRUE;
    glfwInit();
    glfwOpenWindow(800,600, 8,8,8,8,24,8, GLFW_WINDOW);
    glewExperimental = GL_TRUE;
    glewInit();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    while(running)
    {
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        glfwSwapBuffers();
        running = !glfwGetKey(GLFW_KEY_ESC) && gkfwGetWindowParam(GLFW_OPENED);
    }
}

void Example::makeWindowThread()
{
    boost::thread t(simpleWindow);
    t.join();
}

可能有一些无用的代码行(它只是我想要使用的真实方法的一部分的复制粘贴。)两种方法都是静态的。如果我在一个线程中启动交互式控制台并在python中启动pk.makeWindowThread(),我就不能再输入了。如果我将pk.makeWindowThread()的调用也放在python线程中,则不起作用。 (我试图在显示窗口时在控制台中打印一些东西。

2 个答案:

答案 0 :(得分:3)

在保持控制台交互的同时尝试执行进程时,请考虑使用subprocessmultiprocessing模块。在Boost.Python中执行此操作时,使用execv()函数族在C ++中执行进程可能更合适。

在保持控制台交互的同时尝试生成线程时,必须考虑Global Interpreter Lock(GIL)。简而言之,GIL是解释器周围的互斥体,阻止在Python对象上执行并行操作。因此,在任何时间点,允许最多一个线程(已获取GIL的线程)对Python对象执行操作。

对于没有C或C ++线程的多线程Python程序,CPython解释器充当协作调度程序,支持并发。当Python知道线程即将执行阻塞调用时,线程将产生控制。例如,一个线程将在time.sleep()内释放GIL。另外,解释器将在满足某些标准后强制线程产生控制。例如,在线程执行了一定量的字节码操作之后,解释器将强制它产生控制,允许其他线程执行。

C或C ++线程有时在Python文档中称为外来线程。 Python解释器无法强制外部线程通过释放GIL来控制。因此,外来线程负责管理GIL以允许与Python线程并发或并行执行。考虑到这一点,让我们检查一些C ++代码:

void Example::makeWindowThread()
{
  boost::thread t(simpleWindow);
  t.join();
}

这将生成一个线程,thread::join()将阻塞,等待t线程完成执行。如果此函数通过Boost.Python向Python公开,则调用线程将阻塞。由于在任何时间点只允许执行一个Python线程,因此调用线程将拥有GIL。一旦调用线程在t.join()上阻塞,所有其他Python线程将保持阻塞状态,因为解释器无法强制线程产生控制权。要启用其他Python线程,GIL应该在加入前发布,并在后加入时获得。

void Example::makeWindowThread()
{
  boost::thread t(simpleWindow);
  release GIL // allow other python threads to run.
  t.join();
  acquire GIL // execution is going to occur within the interpreter.
}

但是,这仍然会导致控制台阻塞等待线程完成执行。相反,请考虑通过thread::detach()生成线程并从中分离。由于调用线程将不再阻塞,因此不再需要在Example::makeWindowThread内管理GIL。

void Example::makeWindowThread()
{
  boost::thread(simpleWindow).detach();
}

有关管理GIL的更多详细信息/示例,请考虑阅读this答案以获取基本实施概述,并this回答更深入地考虑必须考虑的因素。

答案 1 :(得分:2)

您有两种选择:

  • 使用-i标志启动python,这将导致将其删除到交互式interperter而不是从主线程退出
  • 手动启动交互式会话:

    import code
    code.interact()
    

    如果你想在它自己的线程中运行交互式会话,第二个选项特别有用,因为一些库(如PyQt / PySide)在它们没有从主线程启动时不喜欢它:

    from code import interact
    from threading import Thread
    Thread(target=interact, kwargs={'local': globals()}).start()
    ...  # start some mainloop which will block the main thread
    

    local=globals()传递给interact是必要的,这样您就可以访问模块的范围,否则解释器会话只能访问线程范围的内容。

    < / LI>