Python interpreter crashes when using callback from thread

-1

i have written a Gui-App with pyqt5.

I Use threading.Thread to create a Thread, which does some calculating. The thread gets name, target, args, kwargs and a callback-function which is member of my app class.

The callback works several times, except for the last run. For example, the first 99 calls out of 100 do well, but no. 100 causes the error. After returning from the callback the last time, the interpreter crashes after about a second with an Windows Event, event code 0xc0000005

The callback also has **kwargs as parameters

There is no Traceback from python itsself.

Anyone an idea on what could be the cause or what I do wrong?

Environment:

  • Windows 10,
  • Python 3.9.0,
  • PyQt5 5.15.1

A minimal Example of both classes (probably will not work):

from Controller.filecontroller import Files_Controller as filecontroller

class DialogBatch(QDialog): 
    
    def __init__(self, parent= None):

        #    Initialize super-class
        super(DialogBatch, self).__init__()
        #    Load the GUI Description File, created with QtDesigner
        uic.loadUi('.\\GUI_dialog_batch_ui\\dialog_batch.ui', self)
        
        #    QProgressBars
        self.progressBar_batch_progress = self.findChild(QProgressBar, 'progressBar_batch_progress')
        
        #    QPushButtons
        self.pushButton_batch_start = self.findChild(QPushButton, 'pushButton_batch_start')
        
        ....  

        #    Filecontroller for file-operations
        self.filecontroller = filecontroller()
        
        #    Thread for executing high-level batch operations; 
        self.__batchthread = None

        #    Show GUI
        self.show()

    ....
    # Callback
    def __update_GUI(self, **kwargs):
        """!    Hidden method for updating the GUI
        @param key-only progress: [int] progress of the task executed
        @return: [int]    1 after finishing
        """
        test = deepcopy(kwargs)
        
        print("Callback entered")

        if "progress" in test:
            self.progressBar_batch_progress.setValue(test["progress"])
            
            print("__update_GUI: Callback called!")
        else:
            print("__update_GUI: No Parameter!")
        print("update GUI finished")
        return 1

    ....
    def slot_pushbutton_start_clicked(self):
        ...
        self.__batchthread = threading.Thread(\
                name='Batchthread', \
                target=self.filecontroller.batch_folder,\
                args=(self.input[0], self.signals[0], self.databases),\
                kwargs={"callback":self.__update_GUI})

        self.__batchthread.start()
        
        ...
class Files_Controller(object):
    ##    Constructor
    # @param self
    def __init__(self):
    ...
        self.__killbatchthread = False
        self._func_callback = None
        ...

    ...
    def batch_folder(self, files, signals, databases, *args, **kwargs):
        
        ...
        self.__params = {}
        files_read = 0
        files_painted = 0
        progress = 0
        
            ...
            for each_file in allfiles:
            ...  
                    ....
                    files_read +=1
                    #    Cancel
                    if self.get_killbatchthreat(): return -1

                    #    Callback for Update
                    if self._func_callback is not None:
                        progress = int((files_read+files_painted)*50/number_of_files)
                        self.__params.clear()
                        self.__params={"progress":progress}
                        self._func_callback(**self.__params)

                    ...

                    files_painted +=1
                    #    Callback for GUI update
                    if self._func_callback is not None:
                        progress = int((files_read+files_painted)*50/number_of_files)
                        self.__params.clear()
                        self.__params={"progress":progress}

                        print("Returnvalue: %i" %(self._func_callback(**self.__params)))
                        for i in range(10):
                            print("Sleeptime: %i" %i)
                            time.sleep(1)

                    ....

The last time calling _func_callback with the last file produces this output:

Callback entered __update_GUI: Callback called! update GUI finished Returnvalue: 1 Sleeptime: 0 Sleeptime: 1

After Sleeptime: 1 The python interpreter crashes.

python
multithreading
callback
crash
pyqt5
asked on Stack Overflow Nov 19, 2020 by mikesmitti • edited Nov 20, 2020 by mikesmitti

1 Answer

0

I could solve it myself: With a change in design the problem disappeared.

The problem was using a callback into the gui class (in the gui thread) from a nonw-gui-thread-function. After using signals instead of the callback, it worked fine.

Conclusion: Never call a gui-thread-function from a none-gui-thread function.

answered on Stack Overflow Dec 12, 2020 by mikesmitti

User contributions licensed under CC BY-SA 3.0