Почему многопроцессорные приложения glfw будут остановлены, если `glfw.create_window` выполняется в MainProcess? - PullRequest
0 голосов
/ 07 января 2019

Когда нам нужно запустить многопоточное приложение 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 голосов
/ 07 января 2019

Глядя на ошибку, похоже, она исходит от XCB, подразумевая, что вы работаете в UNIX-подобной операционной системе с сервером X11.

В случае first происходит инициализация GLFW. Затем вы создаете процессы. В UNIX-подобных системах это делается с помощью системного вызова fork(2), который создает идеальную копию родительского процесса, а затем запускает как родительский, так и дочерний процесс. Так что теперь сервер X11 имеет две разных программ, которые разговаривают с ним по одному и тому же соединению и притворяются одинаковыми. Как вы можете себе представить, это не очень хорошо работает.

Кроме того, многие GUI-инструменты (включая glfw) по своему дизайну не являются поточно-ориентированными, а multiprocessing использует фоновую нить для ведения домашнего хозяйства. Я не думаю, что это проблема здесь, но это может быть.

Случай second является вариацией первого; каждый процесс должен иметь свое собственное соединение с X-сервером.

Кстати, glfw.init() возвращает значение, указывающее успех или неудачу. Вы должны обязательно проверить, что glfw был успешно инициализирован, прежде чем продолжить.

...