Почему возникает гонка при вызове QThread.quit() и впоследствии QThread.wait()?

#python #multithreading #qt #qthread #pyside2

#python #многопоточность #qt #qthread #pyside2

Вопрос:

Используя PySide2 , у меня есть вспомогательный поток, выполняющий цикл фоновых событий. После закрытия моего приложения я хотел бы, чтобы quit() вспомогательный поток и wait() для него завершили свои события.

Однако в моем приложении возникает тупик (или что-то в этом роде), как только я вызываю wait() . Чтобы продемонстрировать эту проблему, я создал небольшой образец приложения с подклассом, QThread который запускает цикл событий путем вызова exec_() , а затем имитирует длительное время выхода с некоторыми макетами очистки. отпечатки.

 import sys
import time

from PySide2.QtCore import QThread
from PySide2.QtWidgets import QApplication, QMainWindow


class AuxThread(QThread):

    def __init__(self):
        super().__init__()

    def run(self):
        print("Starting AuxThread")
        self.exec_()
        print("Stopping AuxThread")
        iteration = 0
        # Simulate a long time for thread finish
        while iteration < 100:
            iteration  = 1
            print(f"{iteration} cleanup loops in {QThread.currentThread()}")


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.thread().setObjectName("main thread")

        self.aux_thread = AuxThread()
        self.aux_thread.setObjectName("aux thread")

        self.aux_thread.start()

    def closeEvent(self, event):
        print(f"Quitting aux_thread from {QThread.currentThread()}")
        self.aux_thread.quit()

        # Increasing this time allows the run() function to complete
        # If this time is too short, then execution hangs forever
        time.sleep(0.001)

        print(f"blocking thread {QThread.currentThread()}")
        self.aux_thread.wait()
        print(f"aux_thread is joined")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
  

Вывод этой функции показан ниже, количество напечатанных итераций будет отличаться в зависимости от времени.

 Starting AuxThread
Quitting aux_thread from <PySide2.QtCore.QThread(0x7fcc9cfd12b0, name = "main thread") at 0x11c4f1580>
Stopping AuxThread
1 cleanup loops in <__main__.AuxThread(0x7fcc9cfe5e40, name = "aux thread") at 0x11c4f15c0>
2 cleanup loops in <__main__.AuxThread(0x7fcc9cfe5e40, name = "aux thread") at 0x11c4f15c0>
... [output elided] ...
72 cleanup loops in <__main__.AuxThread(0x7fcc9cfe5e40, name = "aux thread") at 0x11c4f15c0>
73 cleanup loops in <__main__.AuxThread(0x7fcc9cfe5e40, name = "aux thread") at 0x11c4f15c0>
blocking thread <PySide2.QtCore.QThread(0x7fcc9cfd12b0, name = "main thread") at 0x11c4f1580>
  

В документах говорится, что QThread.wait() «блокирует поток до тех пор, пока QThread не завершит выполнение (т. Е. Когда он вернется из run()

Интересно, что они не упоминают, какой поток здесь заблокирован, но не имеет смысла блокировать QThread, который вы ожидаете. Я думаю, aux_thread.wait() следует блокировать только основной поток, почему выполнение во вспомогательном потоке блокируется сразу после wait() вызова?

Чего мне не хватает?

Комментарии:

1. Вы вызываете aux_thread.quit() , поэтому совершенно ясно, какой поток имеется в виду. aux_thread это не основной поток. Кстати. обычно вы не хотите блокировать основной поток 🙂

2.на самом деле, я пытаюсь заблокировать закрытие до aux_thread завершения. Вопрос в том, почему aux_thread.wait() блокируется aux_thread и main_thread

3. Это блокирует поток, в котором вызываются quit и wait , в данном случае основной поток. Потому что он ожидает завершения всех ваших операций aux_thread . Если нет конкретных результатов, которых вам нужно дождаться, вы могли бы вызвать просто quit . Он не должен блокировать aux_thread , он просто завершается, как только может (если вы имеете в виду, почему он не выводит значение 99).

4. Согласно документам, aux_thread не должно быть заблокировано. Но в приведенном мной примере она блокируется при моем вызове aux_thread.wait() Программа никогда не завершается, она вечно зависает при вызове ожидания