0

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

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

这将执行 showExample,它运行一个渲染 3D 内容的窗口。现在我想在这个窗口运行时继续在 python 控制台中编码。上面的示例可以显示窗口,但无法保持控制台交互。任何想法如何做到这一点?感谢您的任何建议。

问候克里斯

编辑:我还尝试在 showExample() C++ 代码中创建线程,但效果不佳。我可能必须使控制台成为线程,但我不知道如何并且找不到任何有用的示例。

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 线程中,则不起作用。(我试图在显示窗口时在控制台中打印一些东西。

4

2 回答 2

3

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

当尝试在保持控制台交互的同时生成线程时,必须考虑全局解释器锁(GIL)。简而言之,GIL 是解释器周围的互斥体,防止对 Python 对象执行并行操作。因此,在任何时间点,最多允许一个线程,即获得 GIL 的线程,可以对 Python 对象执行操作。

对于没有 C 或 C++ 线程的多线程 Python 程序,CPython 解释器用作协作调度程序,从而实现并发。当 Python 知道线程即将执行阻塞调用时,线程将产生控制权。例如,一个线程将在time.sleep(). 此外,在满足某些条件后,解释器将强制线程让出控制权。例如,一个线程执行了一定数量的字节码操作后,解释器会强制它让出控制权,允许其他线程执行。

在 Python 文档中,C 或 C++ 线程有时被称为外来线程。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 的更多详细信息/示例,请考虑阅读答案以获取基本实现概述,并阅读答案以更深入地了解必须考虑的因素。

于 2013-07-17T14:50:05.537 回答
2

你有两个选择:

  • 使用标志启动python -i,这将导致将其放到交互式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()tointeract是必要的,这样您就可以访问模块的范围,否则解释器会话将只能访问线程范围的内容。

于 2013-06-28T11:24:17.247 回答