QApplication в неосновном потоке второго процесса с pyQt4: является ли этот код законным, и если нет, то почему он работает? - PullRequest
0 голосов
/ 17 февраля 2020

Мои соавторы и я разработали интегрированную среду разработки (IDE) в python 2.7 и pyQt4, которая отлично работает уже более десяти лет. Теперь мне нужно перенести его на pyqt5, и я столкнулся с несколькими проблемами. Этот пост связан с моей первой проблемой. Прежде чем объявить его дубликатом, внимательно прочитайте вопросы внизу. Это потому, что я не понимаю ответы в соответствующих постах, которые я задаю здесь, другие точные вопросы.

Архитектура моей IDE следующая:

  • Основное приложение IDE является приложением QApplication, запущенным в первом процессе (скажем, P1)
  • Второй процесс (скажем, P2) создается P1. Основной поток P2 выполняет бесконечное l oop, ожидая выполнения фрагментов кода из P1 (через очередь) в разных неосновных потоках P2.

  • Хотя большинство частей кода, которые должны быть запущены, не являются gui, один (и только один) из неосновного потока P2 - это поток Qt, выполняющий QApplication, который может выполнять части кода Qt.

  • Это QApplication (скажем, приложение) имеет нормальное событие l oop, запущенное с app.exec_ (), но также может получить сигнал с функцией gui, которая будет запущена в качестве параметра соответствующего slot.

Вот код, используемый для этого, который отлично работает. (к сожалению, я не могу вставить сюда автономный код разумного размера, но этого должно быть достаточно, чтобы понять и ответить на вопросы)

"""
This model helps to execute GUI code in a QT thread.
"""    
import time, sys
from threading import Thread 
from PyQt4.QtCore import *
from PyQt4.QtGui import *

#from pyview.identifyThreads import identify

signalConnected = False


def _runGuiCodeSignal(f):
        f()

def execInGui(f):
    _ensureGuiThreadIsRunning()
    global app
    if app == None:
        raise Exception("Invalid application handle!")
    app.emit(SIGNAL("runGuiCode(PyQt_PyObject)"), f)

def _createApplication():
    #from pyview.identifyThreads import identify
    global app
    global signalConnected
    global _runGuiCodeSignal
    app = QApplication(sys.argv)          #
    app.setQuitOnLastWindowClosed(False)  #
    app.connect(app, SIGNAL("runGuiCode(PyQt_PyObject)"), _runGuiCodeSignal, Qt.QueuedConnection | Qt.UniqueConnection)
    signalConnected = True
    if app.thread() != QThread.currentThread():
        raise Exception("Cannot start QT application from side thread! You will have to restart your process...")
    #identify(message='in createApplication just before app.exec')
    app.exec_()


def _ensureGuiThreadIsRunning():
    #from pyview.identifyThreads import identify
    global app
    global signalConnected
    global _runGuiCodeSignal
    app = QApplication.instance()
    if app == None:
       thread = Thread(target=_createApplication)
       #identify('in _ensureGuiThreadIsRunning')
       print "Creating new Qt application in thread ", thread
       thread.daemon = True
       thread.start()
       while thread.is_alive() and (app == None or app.startingUp()):
           time.sleep(0.01)
   else:
       if not signalConnected:
       print app.connect(app, SIGNAL("runGuiCode(PyQt_PyObject)"), _runGuiCodeSignal,
                                  Qt.QueuedConnection | Qt.UniqueConnection)
       signalConnected = True

При определении функции f, которая создает QWindow с различными виджетами, и запустив execin GUI (f) в ЛЮБОМ потоке P2, приложение QApplication создается в новом другом неосновном потоке или извлекается, если оно уже существует (например, в процессе P2 только один QThread), и все работает отлично.

Теперь мои вопросы:

  1. Нарушает ли приведенный выше код какое-либо правило Qt4, поскольку оно запускает QApplication в неосновном потоке?

  2. На какой странице документации QT4 говорится, что запрещено обрабатывать, как мы?

  3. Каково определение основного потока процесса? Поток, выполняющий функцию process.run ()?

  4. Что такое основной поток Qt? Это по определению основной поток процесса или это может быть другой поток?

  5. Почему у нас нет ошибки "QApplication не был создан в главном потоке"?

  6. Как Qt4 распознает, запущено ли событие l oop в главном потоке Процесса?

1 Ответ

0 голосов
/ 01 марта 2020

Многие элементы ответа на заданные здесь вопросы можно найти там (см. Как ответы, так и комментарии, в частности от JK SH).

Подводя итог, значение "основного потока" может быть различным для Qt и для системы, в зависимости от платформы. В linux и windows основной поток для Qt - это просто первый поток, имеющий отношение к Qt (будьте осторожны с импортом во всех других потоках). Это не поток, который запустил process.run (). В OS X ситуация иная, и «основной поток» одинаков как для Qt, так и для процесса. В этом отношении специалисты, похоже, считают эту документацию неточной ...

Итак, предварительные ответы на конкретные вопросы этого поста таковы:

1) Не нарушает ли приведенный выше код какой-либо Правило Qt4, потому что оно запускает QApplication в неосновном потоке?

=> Нет

2) На какой странице документации QT4 говорится, что запрещено обрабатывать, как мы сделали?

=> Нет, потому что "основной поток" никогда не определяется правильно в документации pyQt4

3) Каково определение основного потока процесса? Поток, который выполняет функцию process.run ()?

=> Да

4) Что такое основной поток Qt? По определению это основной поток процесса или это может быть другой поток?

=> Это поток, ссылающийся на первый объект Qt (будьте осторожны с импортом в основной поток процесса). Это не основная нить процесса. Они могут быть разными.

5) Почему у нас нет ошибки "QApplication не был создан в главном потоке"?

=> Поскольку он создан в том, что Qt называет " main thread ", хотя он отличается от того, что процесс называет" main thread ".

6) Как Qt4 распознает, выполняется ли событие l oop в главном потоке процесса?

=> Он просто НЕ работает на windows и linux.

Пожалуйста, исправьте этот ответ, если он содержит какую-либо ошибку.

...