Qthread locking up Gui PySide

久未见 提交于 2019-12-12 09:57:05

问题


I am trying to run a process in a separate thread but it is freezing my Gui and I cant understand why.

I am initialising the thread in the init function of my class:

self.cipher = Cipher()
self.cipher_thread = QThread()
self.cipher.moveToThread(self.cipher_thread)

self.cipher_thread.started.connect(lambda: self.cipher.encrypt(self.plaintext_file_path,
                                                                       self.ciphertext_file_path,
                                                                       self.init_vector,
                                                                       self.key))

self.cipher_thread.start()

The encrypt method of the cipher class is:

def encrypt(self):
    # check that both the key and the initialisation vector are 16 bytes long
    if len(self.k) == self.key_byte_length and len(self.init_vector) == self.byte_length:
        if not self.used:
            self.used = True

            # get the padding bytes and store in a list
            self.padding_bytes = self.__getPaddingBytes()

            # generate sub keys
            # initial subkey is first four words from key
            init_subkey_words = []
            for i in range(0, self.key_byte_length-3,4):
                init_subkey_words.append(self.k[i:i+4])

            self.__genSubKeys(init_subkey_words)

            # read file and append the padding to it
            with open(self.plaintext_file_path, 'rb') as f:
                self.plaintext_data = bytearray(f.read())
            self.plaintext_data += self.padding_bytes

            # set total size
            self.total_size_bytes = len(self.plaintext_data)

            # insert the initialisation vector as the first 16 bytes in the ciphertext data
            self.ciphertext_data = self.init_vector

            '''
            begin encryption
            --------------------------------------------------------------------------------------------------------
            '''
            self.start_time = datetime.datetime.now()
            # loop through the file 16 bytes at a time
            for i in range(0, int(len(self.plaintext_data)), self.byte_length):  # i increases by 16 each loop
                # if self.block_time is not None:
                    # print('block time is', datetime.datetime.now()-self.block_time)
                self.block_time = datetime.datetime.now()

                # set the 16 byte state - bytearray Object
                state = copy.deepcopy(self.plaintext_data[i:i+self.byte_length])

                # xor the state with the initialisation vector and first subkey
                for j in range(self.byte_length):
                    state[j] ^= self.init_vector[j]
                    state[j] ^= self.sub_keys[0][j]

                # round start
                # --------------------------------------------------------------------------------------------------
                for j in range(self.num_rounds):
                    self.current_round += 1     # increment current round counter

                    '''
                    arrange the data into a 4x4 matrix
                    [[1, 5, 9, 13],
                    [2, 6, 10, 14],
                    [3, 7, 11, 15],
                    [4, 8, 12, 16]]
                    '''
                    state_matrix = np.array(state)
                    state_matrix.resize(4, 4)
                    state_matrix.swapaxes(0, 1)

                    # byte substitution
                    # ----------------------------------------------------------------------------------------------
                    for row in state_matrix:
                        for byte in row:
                            byte = self.__sBoxSubstitution(byte)

                    # shift row - row k shifts left k places
                    # ----------------------------------------------------------------------------------------------
                    state_matrix = state_matrix.tolist()
                    for row in range(1, 4):
                        for l in range(0, row):
                            state_matrix[row].append(state_matrix[row].pop(0))
                    state_matrix = np.array(state_matrix)


                    # mix column - not included in last round
                    # ----------------------------------------------------------------------------------------------
                    if self.current_round is not self.num_rounds:
                        # swap axes of state matrix
                        state_matrix.swapaxes(0, 1)

                        # create temporary holder for the computed values
                        mixed_col_bytes = [[], [], [], []]

                        for k in range(4):
                            for l in range(4):
                                mixed_col_bytes[k].append(
                                    self.__GFMult(self.MIX_COL_MATRIX[l][0], state_matrix[k][0]) ^
                                    self.__GFMult(self.MIX_COL_MATRIX[l][1], state_matrix[k][1]) ^
                                    self.__GFMult(self.MIX_COL_MATRIX[l][2], state_matrix[k][2]) ^
                                    self.__GFMult(self.MIX_COL_MATRIX[l][3], state_matrix[k][3]))

                        # restore state matrix from temporary holder and swap axes back
                        state_matrix = np.array(copy.deepcopy(mixed_col_bytes))
                        state_matrix.swapaxes(0, 1)

                    # restore single bytearray state
                    state_matrix = state_matrix.flatten()
                    state_matrix = state_matrix.tolist()
                    state = bytearray(state_matrix)

                    # key addition
                    # ----------------------------------------------------------------------------------------------
                    for k in range(self.byte_length):
                        state[k] ^= self.sub_keys[self.current_round][k]

                self.ciphertext_data += state                    # append state to ciphertext data
                self.init_vector = self.ciphertext_data[-16:]    # update the initialisation vector
                self.current_round = 0                           # reset current round number
                self.completed_size_bytes += self.byte_length
                self.percent_done = (self.completed_size_bytes/self.total_size_bytes)*100

                self.updateProgressSig.emit(int(self.percent_done))
            # finish encryption
            self.__saveEncryptedData()
            print('total encryption time:', datetime.datetime.now() - self.start_time)
            # finish
            self.finish(self.ciphertext_file_path)

    # either the key of the initialisation vector are not the correct length
    else:
        print(' either the key length or initialisation vector is the wrong length')
        print('---')
        print('key length:', len(self.k))
        print('iv length:', len(self.init_vector))

回答1:


The issue you are experiencing is that the function you are connecting to the started signal is not run in the thread, it's run in the context of where it was set, which seems to be your UI thread.

Normally you would want to create a custom class which inherits from QThread, and any code that you want to be executed would be in the run() function of that class. Like so:

class MyTask(QThread):
  def __init__ (self):
    QThread.__init__(self)

  def run(self):
    print("Code to run in the thread goes here.")

If that seems like overkill you could just set the value of self.cipher_thread.run to your own function. Here's an example:

import time
from PySide.QtCore import QThread
from PySide import QtGui

app = QtGui.QApplication("")

def main():
  task = SomeTask()
  thread = QThread()

  # Just some variables to pass into the task
  a, b, c = (1, 2, 3)
  thread.run = lambda: task.runTask(a, b, c)


  print("Starting thread")
  thread.start()

  # Doing this so the application does not exit while we wait for the thread to complete.
  while not thread.isFinished():
    time.sleep(1)

  print("Thread complete")

class SomeTask():
  def runTask(self, a, b, c):
    print a, b, c
    print("runTask Started")
    time.sleep(5)
    print("runTask Complete")


if __name__ == "__main__":
  main()



回答2:


As Ekhumoro suggested, I was running into issues with the GIL. using the Multiprocessing module has worked for me.



来源:https://stackoverflow.com/questions/33147725/qthread-locking-up-gui-pyside

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!