2015-10-15 56 views
1

我想在一個單獨的線程中運行一個進程,但它凍結我的桂,我不明白爲什麼。Qthread鎖定桂PySide

我初始化線程在我班上的初始化函數:

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() 

密碼類的加密方法是:

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)) 
+0

它可能不會有任何區別,但嘗試消除'lambda' - 例如將參數傳遞給'Cipher'構造函數並將信號直接連接到'self.cipher.encrypt'(它應該用'@ QtCore.Slot'裝飾)。如果這沒有影響,那可能就是你遇到了python GIL的問題。在這種情況下,您可能需要切換到[multiprocessing](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing)。 – ekhumoro

+0

我看到你已經爲你的問題增加了一些代碼,但它確實沒有用,因爲它不是一個可運行的測試用例。您需要*大幅*將代碼量減少到可識別阻塞的特定部分的程度。這將允許其他人運行你的測試用例,至少看看他們是否可以重現這個問題。 – ekhumoro

+0

是的,經過一番閱讀後,我很確定你是正確的,我遇到了GIL的問題,因爲我試圖在子線程中實現,所以迄今爲止成功完成了多處理 – user2145312

回答

1

您所遇到的問題是,該功能你正在連接到started信號不在線程中運行,它在設置它的位置的上下文中運行,這似乎是您的UI線程。

正常情況下您希望創建一個繼承自QThread的自定義類,並且您想要執行的任何代碼將位於該類的run()函數中。像這樣:

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

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

如果這似乎有點小題大做,你可以只設置self.cipher_thread.run到自己的函數值。這裏有一個例子:

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() 
+0

雖然我同意這會導致合適的結果,它是不是廣泛承認爲不正確的使用QThread - https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ – user2145312

+0

我發現了有趣的文章 - http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/ ...可能不那麼'不正確' – user2145312

+0

有趣的文章,感謝張貼他們。獲得它的任何運氣? – smont

0

正如Ekhumoro所說,我遇到了與GIL有關的問題。使用Multiprocessing模塊已經爲我工作。