2017-01-30 17 views
2

В следующем коде я стараюсь иметь дело с QThread. В этом исполняемом примере есть три кнопки: первая для начала, вторая для остановки и третья для закрытия. Ну, когда я начинаю задание, он работает как шарм. BUT Когда я хочу, чтобы цикл while остановился, я нажимаю кнопку остановки. И теперь возникает проблема: цикл while не останавливается.PyQt: Как бороться с QThread?

Вы видите, кнопка останова выдает сигнал для вызова метода stop() на TestTask().

Что не так?

from sys import argv 

from PyQt4.QtCore import QObject, pyqtSignal, QThread, Qt, QMutex 

from PyQt4.QtGui import QDialog, QApplication, QPushButton, \ 
    QLineEdit, QFormLayout, QTextEdit 

class TestTask(QObject): 

    def __init__(self, parent=None): 
     QObject.__init__(self, parent) 

     self._mutex = QMutex() 

     self._end_loop = True 

    def init_object(self): 
     while self._end_loop: 
      print "Sratus", self._end_loop 

    def stop(self): 
     self._mutex.lock() 
     self._end_loop = False 
     self._mutex.unlock() 

class Form(QDialog): 
    stop_loop = pyqtSignal() 

    def __init__(self, parent=None): 
     QDialog.__init__(self, parent) 

     self.init_ui() 

    def init_ui(self): 


     self.pushButton_start_loop = QPushButton() 
     self.pushButton_start_loop.setText("Start Loop") 

     self.pushButton_stop_loop = QPushButton() 
     self.pushButton_stop_loop.setText("Stop Loop")  

     self.pushButton_close = QPushButton() 
     self.pushButton_close.setText("Close") 

     layout = QFormLayout() 

     layout.addWidget(self.pushButton_start_loop) 
     layout.addWidget(self.pushButton_stop_loop) 
     layout.addWidget(self.pushButton_close) 

     self.setLayout(layout) 
     self.setWindowTitle("Tes Window") 

     self.init_signal_slot_pushButton() 

    def start_task(self): 

     self.task_thread = QThread(self) 
     self.task_thread.work = TestTask() 
     self.task_thread.work.moveToThread(self.task_thread) 
     self.task_thread.started.connect(self.task_thread.work.init_object) 

     self.stop_loop.connect(self.task_thread.work.stop) 

     self.task_thread.start() 

    def stop_looping(self): 
     self.stop_loop.emit() 

    def init_signal_slot_pushButton(self): 

     self.pushButton_start_loop.clicked.connect(self.start_task) 

     self.pushButton_stop_loop.clicked.connect(self.stop_looping) 

     self.pushButton_close.clicked.connect(self.close) 



app = QApplication(argv) 
form = Form() 
form.show() 
app.exec_() 

ответ

2

stop_loop сигнал преобразуется к событию, и послал к потоку приемника сигнала. Но ваш рабочий объект работает с блокировкой while-loop, и это предотвращает обработку потока любых ожидающих событий в очереди событий. Таким образом, слот, подключенный к сигналу stop_loop, никогда не будет вызываться.

Чтобы обойти эту проблему, вы можете вызвать processEvents в то время как петли, чтобы нить обрабатывать свои отложенные события:

def init_object(self): 
    while self._end_loop: 
     QThread.sleep(1) 
     QApplication.processEvents() 
     print "Status", self._end_loop 

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

class TestTask(QObject): 
    def __init__(self, parent=None): 
     QObject.__init__(self, parent) 
     self._mutex = QtCore.QMutex() 
     self._end_loop = True 

    def stop(self): 
     self._mutex.lock() 
     self._end_loop = False 
     self._mutex.unlock() 

И теперь называет stop() непосредственно из главного потока потокобезопасно.

+0

Кажется, что идия с QMutex() - класс не работает. Я обновил свой код. – Sophus

+0

@Sophus. Он работает, но, как я сказал в своем ответе, вам нужно напрямую вызвать 'stop()'. Поэтому в 'stop_looping' замените emit на' self.task_thread.work.stop() '. Тогда сигнал 'stop_loop' вообще не нужен. – ekhumoro

+0

@ ekhumoro: Вы были правы. Он работает. Спасибо. Не отменяется ли инкапсуляция данных, когда я вызываю метод напрямую? – Sophus