当我们必须运行多线程glfw应用程序时,如果在MainProcess中调用了glfw.create_window()
,则程序将停止。
这基本上是更大的代码的一部分,在该代码中我无法更改体系结构(包括多处理体系结构),但这是可以重现该错误的最少代码。
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
函数之前。为什么会这样呢?
答案 0 :(得分:1)
看着该错误,它似乎来自XCB,这意味着您正在运行具有X11服务器的类UNIX操作系统。
在第一情况下,发生的事情是初始化GLFW。然后创建流程。在类似UNIX的系统上,这可以通过使用fork(2)
系统调用来完成,该系统调用可以完美地复制父进程,然后同时运行父进程和子进程。因此,现在X11服务器具有两个不同的程序,它们使用相同的连接与之交谈,并假装相同。您可以想象,这行不通。
此外,许多GUI工具包(包括glfw)都是设计,不是线程安全的,并且multiprocessing
使用后台线程进行内部管理。我认为这不是问题所在,但可能是这样。
第二个案例是第一个案例的变体;每个进程必须与X服务器都有自己的连接。
BTW,glfw.init()
返回一个指示成功或失败的值。继续之前,您绝对应该检查一下glfw是否已成功初始化。