首页 > 解决方案 > 如果在 MainProcess 中执行 `glfw.create_window`,为什么多进程 glfw 应用程序会停止?

问题描述

当我们必须运行一个多线程的 glfw 应用程序时,如果glfw.create_window()在 MainProcess 中调用了该程序将停止。

这基本上是我无法更改架构(包括多处理架构)的更大代码的一部分,但这是可以重现错误的最小代码。

from multiprocessing import Process, Pipe
import threading, multiprocessing
import glfw

def worker():
    print("[Thread]:", threading.get_ident(), "[Process]:", multiprocessing.current_process())

    glfw.init()
    glfw.window_hint(glfw.VISIBLE, 0)
    glfw.window_hint(glfw.DOUBLEBUFFER, 0)
    context = glfw.create_window(width=640, height=480, title='Invisible window', monitor=None, share=None)
    print("Window was created successfully!")

if __name__ == "__main__":
    ## Uncomment the following line to see the program halt with errors:
    # worker()

    np = 10
    processes = [Process(target=worker) for i in range(np)]

    for p in processes:
        p.daemon = True
        p.start()

    print("LET'S WAIT FOR A LONG TIME!")
    import time
    time.sleep(1000)

第一的

如果我不在glfw.create_window主进程中调用代码将正常工作。但是,如果我在其他进程启动之前调用它(您可以取消注释# worker()以查看此效果),它将导致以下错误(我仅部分复制了输出):

...
XIO:  fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
      after 192 requests (192 known processed) with 15 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
XIO:  fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
      after 192 requests (192 known processed) with 15 events remaining.
XIO:  fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
...

第二# worker():在仍然注释的情况下,glfw.init()必须在worker函数内部,不能全局调用一次,即在worker函数之前。为什么会这样?

标签: pythonpython-multiprocessingglfw

解决方案


查看错误,它似乎来自 XCB,暗示您正在使用 X11 服务器在类 UNIX 操作系统上运行。

在第一种情况下,您会初始化 GLFW。然后创建流程。在类 UNIX 系统上,这是通过使用fork(2)系统调用来完成的,该调用制作父进程的完美副本,然后同时运行父进程和子进程。所以现在 X11 服务器有两个不同的程序使用相同的连接与它交谈并假装相同。可以想象,这并不好用。

此外,许多 GUI 工具包(包括 glfw)在设计上不是线程安全的,并且multiprocessing使用后台线程进行内务处理。我不认为这是这里的问题,但它可能是。

第二种情况是第一种情况的变体每个进程都必须有自己到 X-server 的连接。

顺便说一句,glfw.init()返回一个指示成功或失败的值。在继续之前,您绝对应该检查 glfw 是否已成功初始化。


推荐阅读