Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to turn non-thread safe pyqt program into thread safe program?
Forum Updated to NodeBB v4.3 + New Features

How to turn non-thread safe pyqt program into thread safe program?

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 3 Posters 2.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    freemanl144
    wrote on 10 Aug 2022, 18:19 last edited by
    #1

    I have a PyQt GUI application that will just randomly crash and will not produce an error message at all. The crashes are not consistent. Sometimes it happens immediately and then other times it won't happen for a day or two. I have looked online and I believe that it is a threading issue but I haven't been able to trace down where. I've included an example below. My original program is too large to paste here but the threading I am doing in the smaller example is the exact same way I am handling threading in my larger application.

    I am aware that widgets are not thread safe and that I cannot directly access them from external threads and that I need to use signals but I do not know how to do that.

    I believe that below the issue would be appending to the text box while the process is running, so how do I instead use a signal to do this safely?

    main.py

    import logging
    import os
    import time
    from pathlib import Path
    import sys
    from PyQt5.QtCore import QObject, QThread, pyqtSignal
    from PySide2.QtWidgets import QApplication, QWidget
    from PySide2.QtCore import QFile, QObject
    from PySide2.QtUiTools import QUiLoader
    
    logger_real_time = logging.getLogger(__name__)
    
    
    class ConsoleWindowLogHandler(logging.Handler, QObject):
        sigLog = pyqtSignal(str)
    
        def __init__(self):
            logging.Handler.__init__(self)
            QObject.__init__(self)
    
        def emit(self, log_record):
            message = str(log_record.getMessage())
            self.sigLog.emit(message)
    
    
    class Worker(QThread):
        def __init__(self, func, args):
            super(Worker, self).__init__()
            self.func = func
            self.args = args
    
        def run(self):
            self.func(*self.args)
    
    
    class Widget(QWidget):
        def __init__(self):
            super(Widget, self).__init__()
            self.ui = self.load_ui()
            self.bee = Worker(self.start_a_process, ())
            self.run_main_gui()
    
        def load_ui(self):
            loader = QUiLoader()
            current_path = os.fspath(Path(__file__).resolve().parent / "form.ui")
            ui_file = QFile(current_path)
            if ui_file.open(QFile.ReadOnly):
                self.ui = loader.load(ui_file, self)
                ui_file.close()
                return self.ui
    
        def start_a_process(self):
            print('sleeping')
            for i in range(0, 10):
                self.ui.a_text_edit.append("Entering function")
                time.sleep(1)
                self.ui.a_text_edit.append("Exiting function")
    
        def run_main_gui(self):
            self.ui.start_pb.clicked.connect(self.bee.start)
    
    
    if __name__ == "__main__":
        app = QApplication([])
        widget = Widget()
        widget.show()
        sys._excepthook = sys.excepthook
    
    
        def exception_hook(exctype, value, traceback_val):
            print(exctype, value, traceback_val)
            sys._excepthook(exctype, value, traceback_val)
            sys.exit(1)
    
    
        sys.excepthook = exception_hook
        sys.exit(app.exec_())
    

    form.py

        # -*- coding: utf-8 -*-
    
    ################################################################################
    ## Form generated from reading UI file 'form.ui'
    ##
    ## Created by: Qt User Interface Compiler version 5.15.2
    ##
    ## WARNING! All changes made in this file will be lost when recompiling UI file!
    ################################################################################
    
    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *
    
    
    class Ui_Widget(object):
        def setupUi(self, Widget):
            if not Widget.objectName():
                Widget.setObjectName(u"Widget")
            Widget.resize(310, 184)
            self.start_pb = QPushButton(Widget)
            self.start_pb.setObjectName(u"start_pb")
            self.start_pb.setGeometry(QRect(100, 40, 93, 28))
            self.a_text_edit = QTextEdit(Widget)
            self.a_text_edit.setObjectName(u"a_text_edit")
            self.a_text_edit.setGeometry(QRect(10, 80, 291, 87))
    
            self.retranslateUi(Widget)
    
            QMetaObject.connectSlotsByName(Widget)
        # setupUi
    
        def retranslateUi(self, Widget):
            Widget.setWindowTitle(QCoreApplication.translate("Widget", u"Widget", None))
            self.start_pb.setText(QCoreApplication.translate("Widget", u"Start", None))
        # retranslateUi
    
    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 10 Aug 2022, 18:42 last edited by
      #2

      Hi,

      You have here a pretty nice article about that matter.

      It shows how to use the worker object paradigm to update the GUI from a long running task.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      F 2 Replies Last reply 10 Aug 2022, 18:58
      1
      • S SGaist
        10 Aug 2022, 18:42

        Hi,

        You have here a pretty nice article about that matter.

        It shows how to use the worker object paradigm to update the GUI from a long running task.

        F Offline
        F Offline
        freemanl144
        wrote on 10 Aug 2022, 18:58 last edited by
        #3

        @SGaist I'll look into it. Thank you

        1 Reply Last reply
        0
        • S SGaist
          10 Aug 2022, 18:42

          Hi,

          You have here a pretty nice article about that matter.

          It shows how to use the worker object paradigm to update the GUI from a long running task.

          F Offline
          F Offline
          freemanl144
          wrote on 11 Aug 2022, 15:57 last edited by freemanl144 8 Nov 2022, 16:02
          #4

          @SGaist Okay so I looked at what you sent yesterday and have come up with this so far

          class WorkerThread(QThread):
              update_progress = pyqtSignal(str)
          
              def get_message(self, message):
                  self.message = message
          
              def run(self):
                  self.update_progress.emit(self.message)
          

          In main class

              def write_to_log_box(self, message):
                  try:
                      self.worker = WorkerThread()
                      self.worker.get_message(message)
                      self.worker.start()
                      self.worker.update_progress.connect(self.evt_update_progress)
                  except (Exception, ):
                      print("Failure")
          
              def evt_update_progress(self, message):
                  self.ui.tb_log_window.append(message)
          

          This will output one log message but then it crashes. Am I on the right track here? Do I have to call start every single time that I want to send a message to the log box?

          This is being triggered by every time I want to log a message to my message box I am calling write_to_log_box and passing in a message

          1 Reply Last reply
          0
          • S Offline
            S Offline
            SGaist
            Lifetime Qt Champion
            wrote on 11 Aug 2022, 17:22 last edited by
            #5

            Can you explain more precisely the type of workload you want to implement that is threaded ?

            Your minimal object here does make much sense in terms of exploiting threads as it will only run once so it's an overkill.

            In any case, you should setup all connections before starting a thread.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            F 1 Reply Last reply 11 Aug 2022, 17:31
            0
            • S SGaist
              11 Aug 2022, 17:22

              Can you explain more precisely the type of workload you want to implement that is threaded ?

              Your minimal object here does make much sense in terms of exploiting threads as it will only run once so it's an overkill.

              In any case, you should setup all connections before starting a thread.

              F Offline
              F Offline
              freemanl144
              wrote on 11 Aug 2022, 17:31 last edited by
              #6

              @SGaist All I am trying to do is set up a log window. The application will run through a set of measurements and then report those values back to the log window, about 10 every second

              I am attempting to turn the smaller threading example that I currently have into a larger one that I am using in my main application.

              JonBJ 1 Reply Last reply 11 Aug 2022, 18:50
              0
              • F freemanl144
                11 Aug 2022, 17:31

                @SGaist All I am trying to do is set up a log window. The application will run through a set of measurements and then report those values back to the log window, about 10 every second

                I am attempting to turn the smaller threading example that I currently have into a larger one that I am using in my main application.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on 11 Aug 2022, 18:50 last edited by
                #7

                @freemanl144
                Normally you have the (one) worker thread continually running away busy doing computations. From time to time it emits a progress message. The main UI thread has a slot on that signal and puts the passed message into a visual widget.

                1 Reply Last reply
                0

                1/7

                10 Aug 2022, 18:19

                • Login

                • Login or register to search.
                1 out of 7
                • First post
                  1/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved