如果在 MainProcess 中执行“glfw.create_window”,为什么多进程 glfw 应用程序会停止?
Why multi process glfw applications will halt if `glfw.create_window` is executed in the MainProcess?
当我们必须 运行 多线程 glfw 应用程序时,如果 glfw.create_window()
已在 MainProcess 中调用,程序将停止。
这基本上是我无法更改架构(包括多处理架构)的更大代码的一部分,但这是可以重现错误的最少代码。
- 操作系统: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
函数之前。为什么会这样?
看错误,好像是XCB的,说明你是运行类UNIX操作系统,X11服务器。
在第一种情况下,您初始化了 GLFW。然后创建流程。在类 UNIX 系统上,这是通过使用 fork(2)
系统调用完成的,该系统调用完美地复制了父进程,然后同时运行父进程和子进程。所以现在 X11 服务器有 两个 不同的程序使用相同的连接并假装相同。正如您所想象的那样,这并不能很好地工作。
此外,许多 GUI 工具包(包括 glfw)设计 不是线程安全的,multiprocessing
使用后台线程进行管理。我不认为这是这里的问题,但它可能是。
第二个案例是第一个的变体;每个进程必须有自己的到 X 服务器的连接。
顺便说一句,glfw.init()
returns 表示成功或失败的值。在继续之前,您一定要检查 glfw 是否已成功初始化。
当我们必须 运行 多线程 glfw 应用程序时,如果 glfw.create_window()
已在 MainProcess 中调用,程序将停止。
这基本上是我无法更改架构(包括多处理架构)的更大代码的一部分,但这是可以重现错误的最少代码。
- 操作系统: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
函数之前。为什么会这样?
看错误,好像是XCB的,说明你是运行类UNIX操作系统,X11服务器。
在第一种情况下,您初始化了 GLFW。然后创建流程。在类 UNIX 系统上,这是通过使用 fork(2)
系统调用完成的,该系统调用完美地复制了父进程,然后同时运行父进程和子进程。所以现在 X11 服务器有 两个 不同的程序使用相同的连接并假装相同。正如您所想象的那样,这并不能很好地工作。
此外,许多 GUI 工具包(包括 glfw)设计 不是线程安全的,multiprocessing
使用后台线程进行管理。我不认为这是这里的问题,但它可能是。
第二个案例是第一个的变体;每个进程必须有自己的到 X 服务器的连接。
顺便说一句,glfw.init()
returns 表示成功或失败的值。在继续之前,您一定要检查 glfw 是否已成功初始化。