如果在MainProcess中执行`glfw.create_window`,为什么多进程glfw应用程序会停止?

时间:2019-01-06 21:51:35

标签: python python-multiprocessing glfw

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

这基本上是更大的代码的一部分,在该代码中我无法更改体系结构(包括多处理体系结构),但这是可以重现该错误的最少代码。

  • 操作系统:Linux Ubuntu 16.04(Xenial)
  • Python版本:3.6
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函数之前。为什么会这样呢?

1 个答案:

答案 0 :(得分:1)

看着该错误,它似乎来自XCB,这意味着您正在运行具有X11服务器的类UNIX操作系统。

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

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

第二个案例是第一个案例的变体;每个进程必须与X服务器都有自己的连接。

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