簡體   English   中英

發出完成信號后 QThread 出現未知錯誤

[英]Unknown error with QThread after emiting finished signal

我正在 PyQt5 中構建一個應用程序。 我的代碼中有一個計算需求很高的點需要很長時間,所以為了防止 GUI 凍結,我使用了 QThrads。 我有一個 Proces 線程來進行計算,但我使用不同的線程來給用戶反饋(在進度條的幫助下),程序實際上正在運行。 我需要這樣做,因為計算發生在塊中,所以我無法根據計算的 state 更新我的進度條。 我基於相同的方法創建了 2 個線程和 2 個工作線程,但是當我發出第二個工作線程的完成信號(表示工作已完成)時,程序崩潰並拋出錯誤而沒有解釋。 有時在調試情緒中也會發生同樣的情況。

發生相同問題的示例:

主要的:

import sys
from Workers import LoadingWorker, ProcessWorker
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QProgressBar, QListWidget

class Window(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.clicksCount = 0
        self.setupUi()

def setupUi(self):
    # Create widgets
    self.setWindowTitle("MRE")
    self.resize(300, 150)
    self.centralWidget = QWidget()
    self.setCentralWidget(self.centralWidget)
    self.progressBar = QProgressBar()
    self.progressBar.setValue(0)
    self.progressBar.setTextVisible(False)
    self.list = QListWidget()
    self.Btn = QPushButton("Do Stuff", self)
    # Set the layout
    layout = QVBoxLayout()
    layout.addWidget(self.progressBar)
    layout.addWidget(self.list)
    layout.addWidget(self.Btn)
    self.centralWidget.setLayout(layout)
    self.data = None
    self.runtime = 0
    # Add callbacks
    self.Btn.clicked.connect(self.btn_licked)

def btn_licked(self):
    # Call functions to start threads
    self.loading()
    self.process()

def process(self):
    # Set up process worker and get it running
    self.ThreadProcess = QThread()
    self.WorkerProceess = ProcessWorker()
    self.WorkerProceess.moveToThread(self.ThreadProcess)
    self.ThreadProcess.started.connect(self.WorkerProceess.run)
    self.WorkerProceess.finished.connect(self.ThreadProcess.quit)
    self.WorkerProceess.finished.connect(self.WorkerProceess.deleteLater)
    self.ThreadProcess.finished.connect(self.ThreadProcess.deleteLater)
    self.WorkerProceess.progress.connect(self.process_progress)
    self.ThreadProcess.start()
    self.ThreadProcess.finished.connect(self.process_end)

def process_end(self):
    self.WorkerLoading.done = True

def process_progress(self, data, runtime):
    self.data = data
    self.runtime = runtime
    # Some operations on data


def loading(self):
    # Set up loading worker and get it running
    self.ThreadLoading = QThread()
    self.WorkerLoading = LoadingWorker()
    self.WorkerLoading.moveToThread(self.ThreadLoading)
    self.ThreadLoading.started.connect(self.WorkerLoading.run)
    self.WorkerLoading.finished.connect(self.ThreadLoading.quit)
    self.WorkerLoading.finished.connect(self.WorkerLoading.deleteLater)
    self.WorkerLoading.finished.connect(self.ThreadLoading.deleteLater)
    self.WorkerLoading.progress.connect(self.loading_progress)
    self.ThreadLoading.start()
    self.ThreadLoading.finished.connect(self.loading_end)

def loading_progress(self, val):
    self.progressBar.setValue(val)

def loading_end(self,):
    print("Stepped into loading ended")
    self.list.addItem("Runtime (s): " + str(self.runtime))
    self.progressBar.setValue(0)


app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

工人階級:

from time import sleep
from PyQt5.QtCore import QObject, pyqtSignal
import numpy as np
from time import time


class ProcessWorker(QObject):
    finished = pyqtSignal()
    progress = pyqtSignal(np.ndarray, float)

    def run(self):
        start_time = time()
        data = np.random.random(size=(50, 500000))
        data = np.fft.fft(np.linalg.pinv(data))
        runtime = time() - start_time
        self.progress.emit(data, runtime)
        self.finished.emit()



class LoadingWorker(QObject):
    finished = pyqtSignal()
    progress = pyqtSignal(int)
    done = False

    def run(self):
        cnt=0
        while (not self.done):
            cnt+=1
            if cnt==101:
                cnt=0
                sleep(0.1)
            sleep(0.005)
            self.progress.emit(cnt)
        self.finished.emit()
        print("loading finish sign supposedly emitted")

另一件有趣的事是,錯誤不會一直發生。 我得到的錯誤:進程以退出代碼-1073740791(0xC0000409)完成。 我試圖調試它,但我無法找出問題的原因。

當工作人員完成時,您正在刪除線程,因此您會遇到某種競爭條件:當工作人員的finished信號發出時,線程仍在運行,您要求它退出並刪除它; 因為此時線程仍在運行,這會產生問題。

您應該在線程完成后刪除線程。

改變這個:

self.WorkerLoading.finished.connect(self.ThreadLoading.deleteLater)

對此:

self.ThreadLoading.finished.connect(self.ThreadLoading.deleteLater)

請注意,對於像這樣的簡單情況,您可以只繼承 QThread,實現它的run()start()它。
這使事情變得更容易,因為您只有一個 object 可供參考。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM