#python #multithreading #qt #pyqt
#python #многопоточность #qt #pyqt
Вопрос:
Я пытался использовать self.terminate()
в классе QThread, а также self.thread.terminate()
в классе GUI. Я также пытался использовать self.wait()
оба случая. Однако возможны два сценария:
1) Поток вообще не завершается, и графический интерфейс зависает в ожидании завершения потока. Как только поток завершается, графический интерфейс размораживается, и все возвращается в нормальное русло.
2) Поток действительно завершается, но в то же время он замораживает все приложение.
Я также пробовал использовать self.thread.exit()
. Никакой радости.
Чтобы еще раз уточнить, я пытаюсь реализовать кнопку прерывания пользователя в графическом интерфейсе, которая завершила бы выполнение потока в любой момент времени.
Заранее спасибо.
Редактировать:
Вот run()
метод:
def run(self):
if self.create:
print "calling create f"
self.emit(SIGNAL("disableCreate(bool)"))
self.create(self.password, self.email)
self.stop()
self.emit(SIGNAL("finished(bool)"), self.completed)
def stop(self):
#Tried the following, one by one (and all together too, I was desperate):
self.terminate()
self.quit()
self.exit()
self.stopped = True
self.terminated = True
#Neither works
И вот метод класса GUI для прерывания потока:
def on_abort_clicked(self):
self.thread = threadmodule.Thread()
#Tried the following, also one by one and altogether:
self.thread.exit()
self.thread.wait()
self.thread.quit()
self.thread.terminate()
#Again, none work
Комментарии:
1. Примечание: self.terminate === (self.terminated = true), не более того. Для 99% всех реализаций.
2. Спасибо, но это на самом деле не помогает решить проблему.
3. Есть только один способ безопасно завершить поток — позволить ему завершить все ИТ-задачи. Чтобы выполнить это, вы должны проверить thread.terminated перед выполнением сложных задач.
4. Ну, это, конечно, не то, что я ищу.
Ответ №1:
Из документации Qt для QThread::terminate:
Предупреждение: эта функция опасна, и ее использование не рекомендуется. Поток может быть завершен в любой точке его пути к коду. Потоки могут быть завершены при изменении данных. У потока нет возможности очистить после себя, разблокировать любые удерживаемые мьютексы и т. Д. Короче говоря, используйте эту функцию только в случае крайней необходимости.
Вероятно, гораздо лучше переосмыслить свою стратегию обработки потоков таким образом, чтобы вы могли, например, использовать QThread::quit(), чтобы сигнализировать потоку о чистом завершении, а не пытаться заставить поток завершиться таким образом. На самом деле вызов thread.exit() из потока должен делать это в зависимости от того, как вы реализовали run() . Если вы хотите поделиться кодом для вашего метода выполнения потока, который может подсказать, почему он не работает.
Комментарии:
1. Хм. И я предполагаю
self.create()
, что метод является трудоемким методом в потоке? Обычно то, что вы бы сделали там, выглядит примерно такwhile not self.terminated() { do slow operation parts.. }
. К сожалению, я не очень хорошо знаю Python, но, похоже, здесь есть руководство по потоковой передаче, которое может помочь2. Я тоже пробовал это. Это несколько сработало (графический интерфейс не зависал, но поток также не завершался). Однако только что произошло самое странное. Я удалил весь
def stop(self)
код в потоке иdef on_abort_clicked(self)
код в графическом интерфейсе и переписал его. Я просто ввелself.terminate()
функцию потокаstop()
и сделалself.thread.stop()
это в классе GUI. Это работает как шарм. AFAIK, это первое, что я попробовал, и раньше это не работало. Вероятно, я что-то пропустил.
Ответ №2:
Это то, что я сделал:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
stop_flag = 1
...
#=========500 ms class ===================
class Timer500msThread(QThread):
signal_500ms = pyqtSignal(str)
....
def timer500msProcess(self):
if MainWindow.stop_flag == 0 :
self.timer_500ms.stop()
#==========
#=========Main Window ===================
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
MainWindow.stop_flag=0 #this sets the flag to 0 and when the next 500ms triggers the
#the thread ends
print("Program Ending")
Ответ №3:
У меня была похожая проблема , и я решил ее с помощью pyqtSignals
and pyqtSlots
. Вы можете создать a pyqtSignal
в своем MainWindow-классе и использовать aboutToQuit
-function для своего QApplication
экземпляра. Затем вы соединяете эту aboutToQuit
функцию с другой, которая передает сигнал в слот в вашем отдельном потоке. Затем вы можете определить stop()
функцию в этом потоке, которая запускается при отправке сигнала. В этом случае поток не будет завершаться во время его работы.
MainWindow:
class mainSignals(QObject):
isClosed = pyqtSignal()
class mainwindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(mainwindow, self).__init__()
self.mainSignal = mainSignals()
...
...
if __name__ = "__main__":
# This function runs if the application is closed.
# (app.aboutToQuit.connect(windowClose))
def windowClose():
window.mainSignal.isClosed.emit() # Emit the signal to the slot in (sepThread)
app = QApplication(sys.argv)
app.aboutToQuit.connect(windowClose)
window = mainwindow()
window.show()
sys.exit(app.exec())
Септред:
class sepThread(QRunnable):
def __init__(self, parent):
super(sepThread,self).__init__()
self._parent = parent
self.mainOpen = True
self._parent.mainSignal.isClosed.connect(self.stopThread)
# If the signal was emitted by the Mainapplication
# the stopThread function runs and set the mainOpen-attribute to False
def stopThread(self):
self.mainOpen = False
def run(self):
while self.mainOpen == True:
# Do something in a loop while mainOpen-attribute is True
...
...