Results 1 to 5 of 5

Thread: QThread does not work as it is supposed to do...

  1. #1
    Join Date
    Jan 2015
    Posts
    11
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default QThread does not work as it is supposed to do...

    Dear all,

    I would like to use QThread for my app for computational demanding methods. Up to now, I was sublassing QThread and reimplemented the run() method. And it worked actually. Last week-end, I read several blogs, including the one of one Qt developer, that say that this is not the way to do things. Instead, it is better to create a worker that does the task and to move that worker to a thread using the moveToThread method. I managed to create a minimal example that worked with that method. I then tried to do the same using a QMainWindow, and it stopped working. I spent some time trying to understand what was wrong with my code, and was not able to find it. May be one of you can help me?

    Here is a minimal python example. Both ways to use threads are implemented. If you want to test it with a QThead, please comment line 41 and uncomment line 42. If you want to use the worker method, just do the opposite. The code displays the id of the thread in the terminal and is connected to a label in the statusbar (if added using the 'add widget' entry in the file menu). Using the QThread method, everything works perfectly. The gui remains responsive and the label is updated correctly. Using the worker method, the gui is frozen and the label is updated once the thread has finished its job.

    Any help would be highly appreciated and thank you in advance for your time.

    If that help, I work on Archlinux using python 3.6 and PyQt 5.7.

    Best regards,

    Vincent

    Here is the code :
    Qt Code:
    1. from PyQt5 import QtWidgets, QtCore, QtGui
    2. import sys, time
    3.  
    4. class Worker(QtCore.QObject):
    5. sigStatusChanged = QtCore.pyqtSignal(int)
    6. sigTaskFinished = QtCore.pyqtSignal()
    7. def __init__(self):
    8. QtCore.QObject.__init__(self)
    9.  
    10. def task(self):
    11. for n in range(10):
    12. time.sleep(0.1)
    13. self.sigStatusChanged.emit(n)
    14. print('thread : ', int(self.thread().currentThreadId()))
    15. self.sigTaskFinished.emit()
    16.  
    17. class Thread(QtCore.QThread):
    18. sigStatusChanged = QtCore.pyqtSignal(int)
    19. sigTaskFinished = QtCore.pyqtSignal()
    20. def __init__(self, parent):
    21. QtCore.QThread.__init__(self, parent)
    22.  
    23. def run(self):
    24. for n in range(10):
    25. time.sleep(0.1)
    26. self.sigStatusChanged.emit(n)
    27. print('thread : ', int(self.thread().currentThreadId()))
    28. self.sigTaskFinished.emit()
    29.  
    30. class MainWindow(QtWidgets.QMainWindow):
    31. def __init__(self):
    32. QtWidgets.QMainWindow.__init__(self)
    33. self.setWindowTitle("Test de QThread")
    34. self.statusBar().showMessage('Welcome', 1000)
    35. self.mdiArea = QtWidgets.QMdiArea()
    36. self.setCentralWidget(self.mdiArea)
    37. self.lbl = None
    38.  
    39. fileMenu = self.menuBar().addMenu('File')
    40.  
    41. threadAction = QtWidgets.QAction('Thread', self)
    42. #threadAction.triggered.connect(self.threadWithWorker)
    43. threadAction.triggered.connect(self.threadWithThread)
    44.  
    45. addWidgetAction = QtWidgets.QAction('Add Widget', self)
    46. addWidgetAction.triggered.connect(self.addWidget)
    47. removeWidgetAction = QtWidgets.QAction('Remove Widget', self)
    48. removeWidgetAction.triggered.connect(self.removeWidget)
    49.  
    50. fileMenu.addAction(threadAction)
    51. fileMenu.addAction(addWidgetAction)
    52. fileMenu.addAction(removeWidgetAction)
    53.  
    54. print('app : ', int(self.thread().currentThreadId()))
    55.  
    56. def threadWithWorker(self):
    57. def stopThread():
    58. thread.quit()
    59. thread.wait()
    60. thread = QtCore.QThread()
    61. thread.start()
    62. worker = Worker()
    63. worker.moveToThread(thread)
    64. worker.sigTaskFinished.connect(stopThread)
    65. worker.sigStatusChanged.connect(self.updateStatus)
    66. worker.task()
    67.  
    68. def threadWithThread(self):
    69. thread = Thread(self)
    70. QtCore.QCoreApplication.processEvents()
    71. thread.sigStatusChanged.connect(self.updateStatus)
    72. thread.start()
    73.  
    74. def updateStatus(self, val):
    75. if self.lbl is not None:
    76. self.lbl.setText(str(val))
    77.  
    78. def addWidget(self):
    79. self.lbl = QtWidgets.QLabel('Test')
    80. self.statusBar().addWidget(self.lbl)
    81.  
    82. def removeWidget(self):
    83. if self.lbl is not None:
    84. self.statusBar().removeWidget(self.lbl)
    85.  
    86. if __name__ == '__main__':
    87. app = QtWidgets.QApplication(sys.argv)
    88. view = MainWindow()
    89. view.show()
    90. app.exec_()
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QThread does not work as it is supposed to do...

    Quote Originally Posted by Vincent Le Saux View Post
    Up to now, I was sublassing QThread and reimplemented the run() method. And it worked actually.
    I would have kept using the solution that is known to work

    Quote Originally Posted by Vincent Le Saux View Post
    Last week-end, I read several blogs, including the one of one Qt developer, that say that this is not the way to do things. Instead, it is better to create a worker that does the task and to move that worker to a thread using the moveToThread method.
    If you ask me that article is complete nonsense.

    This approach is nice if your worker task needs an event loop, but just overhead if the task is running a single blocking function.

    Quote Originally Posted by Vincent Le Saux View Post
    I managed to create a minimal example that worked with that method. I then tried to do the same using a QMainWindow, and it stopped working.
    You are calling "task()" in the context of the main thread.

    Cheers,
    _

  3. The following user says thank you to anda_skoa for this useful post:

    Vincent Le Saux (14th January 2017)

  4. #3
    Join Date
    Jan 2015
    Posts
    11
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QThread does not work as it is supposed to do...

    Hi anda_skoa,

    Thank you for your reactivity. It is highly appreciated. I have two remarks after reading your response.

    1. Could you be more precise about the 'non sense' nature of the article? I do not know that much, so any tip/comment is welcomed

    2. I do not understand your last remark about the "task()" method. Is it the reason why it is not working? If yes, why? And what would the fix look like?

    3. (I know, I said three) One advantage, according to what I read, is that it is easier to stop a thread using the worker approach (do not ask me why, I don't know ). How can I stop a thread using the QThread approach (the one that works)? Just calling thread.quit()?

    Thank you very much.

    Regards,

    Vincent

  5. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QThread does not work as it is supposed to do...

    Quote Originally Posted by Vincent Le Saux View Post
    1. Could you be more precise about the 'non sense' nature of the article? I do not know that much, so any tip/comment is welcomed
    It claims that the worker object approach is the best approach for all cases, which it is not.

    The approach to reimplement run() is fine, even better, for certain type of paralllel tasks, e.g. single long running functions, single continuously running functions, etc.

    The worker object approach is nicer for event processsing tasks, but unnecessarily complex for tasks that don't need that.

    Quote Originally Posted by Vincent Le Saux View Post
    2. I do not understand your last remark about the "task()" method. Is it the reason why it is not working? If yes, why? And what would the fix look like?
    In your threadWithWorker method you create a thread, start it and then just let is sit idly in its event loop.
    Then you create a worker object and execute its task() method in the main thread.

    Quote Originally Posted by Vincent Le Saux View Post
    3. (I know, I said three) One advantage, according to what I read, is that it is easier to stop a thread using the worker approach (do not ask me why, I don't know ).
    See, that's why the article it nonsense.
    That assumes the worker task is event loop driven, so simply shutting down the thread's event loop would end the thread and the processing.

    For a non-event driven task, like in your case, it is more complicated because you need to end the task and the thread.

    Quote Originally Posted by Vincent Le Saux View Post
    How can I stop a thread using the QThread approach (the one that works)? Just calling thread.quit()?
    You don't need quit() because the thread is not running its event loop.
    You need to stop the task, e.g. exit the loop.
    The thread ends once run() returns.

    Cheers,
    _

  6. #5
    Join Date
    Jan 2015
    Posts
    11
    Thanks
    1
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QThread does not work as it is supposed to do...

    OK, things are clearer for me now. I'll keep using the QThread approach (the one that works ).

    Thank you very much of your time!

    Regards,

    Vincent

Similar Threads

  1. How am I supposed to link LibTIFF library?
    By J. Doe in forum Newbie
    Replies: 1
    Last Post: 30th November 2016, 17:01
  2. Replies: 7
    Last Post: 9th October 2015, 17:18
  3. Replies: 0
    Last Post: 5th February 2013, 22:16
  4. Replies: 1
    Last Post: 14th April 2011, 10:58
  5. QThread doent work for QSound
    By anafor2004 in forum Qt Programming
    Replies: 2
    Last Post: 19th November 2008, 17:00

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.