如何在从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线程中,则不起作用。 (我试图在显示窗口时在控制台中打印一些东西。
答案 0 :(得分:3)
在保持控制台交互的同时尝试执行进程时,请考虑使用subprocess
或multiprocessing
模块。在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
是必要的,这样您就可以访问模块的范围,否则解释器会话只能访问线程范围的内容。