iT邦幫忙

0

Linux下PyQt5 如何解決死機以及double free or corruption(!prev) Aborted(core dumped)?

  • 分享至 

  • xImage

各位大大好

最近在嘗試切換不同系統下GUI運作情況
在原先Winows下
能進行Compare建置工作
所有功能都正常運作

但切換至Linux下
透過QProcess進行Compare時
過程中一定會發生視窗崩潰(無回應整個卡死)
有時會跳出警告就閃退
double free or corruption(!prev)
Aborted(core dumped)

有嘗試過不使用waitForFinished(-1)
但這樣就會導致Compare的輸出不完全就結束

也嘗試過使用thread.Thread方式去建置多線程
worker = threading.Thread(target=self.process_single_program, args=(id,))

    def run_build(self, status):
        try:
            self.run_build_ui_control(status)
            if status == "Start":
                if self.bool_paused_job
                    self.bool_paused_job = False
                    self.main.status_label.setText('Building')
                    for job in list(self.queue_backup.queue):
                        self.queue_job.put(job)
                        self.list_processes.append(job)
                    self.create_worker_threads()

                else:
					if not self.try_lock_socket():
						self.main.status_label.setText('Wait')
						self.thread_lock = threading.Thread(
							target=self.wait_for_lock)
						self.thread_lock.start()
						return

            elif status == "Pause":
                self.bool_paused_job = True
                for job in self.list_current_job:
                    if job not in list(self.queue_backup.queue):
                        self.queue_backup.put(job)
                self.terminate_all_subprocesses()
                self.clear_job_queue()

            elif status == "Terminate":
                if self.bool_paused_job:
                    self.bool_paused_job = False
                else:
                    self.terminate_all_subprocesses()
                    self.clear_job_queue()
                self.stop_job = True
                self.clear_backup_queue()
                self.release_lock_socket()
        except Exception as e:
            logging.exception(f"[StartBuild]{e}")

	def put_jobs(self):
        try:
            for job in self.list_processes:
                job.disconnect_singals()
            self.list_processes.clear()
            self.set_first_process_build.clear()
            first_process_for_build = {}
            sorted_build_command = sorted(self.dict_build_command.items(), key=lambda x: x[0])
            for build_name, cmd in sorted_build_command:
                for list_name in self.dict_table_console_window.keys():
                    if build_name in list_name:
                        tab_idx = list(self.dict_table_console_window).index(list_name)
                        print(f'Now Building: {list_name}, Table Index: {tab_idx}')
                        ui = self.dict_table_console_window[list_name]
                        ui.clear_text_broswer()
                        job = Job(build_name, cmd, ui)
                        if build_name not in first_process_for_build:
                            first_process_for_build[build_name] = job
                            job.task_started.connect(partial(self.build_result, tab_idx, build_name, 'building'))
                            job.task_msg.connect(partial(self.stdout, job, ui))
                            job.task_fail_result.connect(partial(self.build_result, tab_idx, build_name, 'fail'))
                            job.task_pass_result.connect(partial(self.build_result, tab_idx, build_name, 'pass'))
                            self.queue_job.put(job)
                            self.queue_backup.put(job)
                            self.list_processes.append(job)
                            job.task_finished.connect(partial(self.sync_task_finish, job))
                        else:
                            first_process = first_process_for_build[build_name]
                            first_process.task_started.connect(partial(self.build_result, tab_idx, build_name, 'building'))
                            first_process.task_msg.connect(partial(self.stdout, job, ui))
                            first_process.task_fail_result.connect(partial(self.build_result, tab_idx, build_name, 'fail'))
                            first_process.task_pass_result.connect(partial(self.build_result, tab_idx, build_name, 'pass'))
                            continue
        except Exception as e:
            logging.exception(f"[PutJobinQueue] {e}")

    def create_worker_threads(self):
        try:
            self.NUM_OF_WORKER_THREAD = 2
			self.work_threads = []
            for id in range(self.NUM_OF_WORKER_THREAD):
                worker = WorkerThread(self.process_single_program, id)
				self.work_threads.append(worker)
				worker.finished.connect(worker.deleteLater)
                worker.start()
            logging.info(f"[CreateWorkerThreads] Created successfully.")
        except Exception as e:
            logging.exception(f"[CreateWorkerThreads]{e}")

    def process_single_program(self, t_id):
        while not self.stop_job:
            try:
                with self.lock_get_job:
                    if not self.queue_job.empty():
                        job = self.queue_job.get()
                        self.list_current_job.append(job)
                    else:
                        break
                if job is not None:
                    job.run()
                    self.queue_job.task_done()
                    self.list_current_job.remove(job)
                    if not self.bool_paused_job:
                        self.queue_backup.get()
            except Exception as e:
                logging.exception(f"[Process_Single_Program] {e}")

    def stdout(self, job, ui, stdout):
        try:
            self.stdout_buffer.append((job, ui, stdout))
            if not self.refresh_stdout_timer.isActive():
                self.refresh_stdout_timer.start(1500)
        except Exception as e:
            logging.exception(f'[PrintStdout] {e}')

    def update_stdout(self):
        try:
            for job, ui, stdout in self.stdout_buffer:
            
                format = QTextCharFormat()
                cursor = ui.textBrowser.textCursor()
                cursor.movePosition(cursor.End)

                if self.pattern_title.search(stdout) or self.pattern_warn.search(stdout):
                    format.setForeground(QColor("yellow"))
                elif 'Fail' in stdout:
                    format.setForeground(QColor("red"))
                elif 'Pass' in stdout:
                    format.setForeground(QColor("green"))
                else:
                    format.setForeground(QColor("white"))
                cursor.insertText(f"{stdout}\n", format)
            self.stdout_buffer = []
            QApplication.processEvents()
        except Exception as e:
            logging.exception(f"[UpdateStdout] {e}")

    def build_result(self, tab_idx, build_name, result):
        try:
            tab = self.main.tabWidget.widget(tab_idx)
            if result == 'pass':
				build = 'PASS'
                if build_name not in self.set_first_process_build:
                    self.int_build_pass = self.int_build_pass + 1 
                    self.set_first_process_build.add(build_name)
            elif result == 'fail':
				build = 'FAIL'
                if build_name not in self.set_first_process_build:
                    self.int_build_fail = self.int_build_fail + 1
                    self.set_first_process_build.add(build_name)
            elif result == 'building':
                build = 'building'
			
			table_build_result = tab.tab_toolbar.findChild(QtWidgets.QLabel, "table_build_result")
            table_build_result.setText(build)

            self.main.build_label.setText(f'Build PASS: {self.int_build_pass}')

        except Exception as e:
            logging.exception(f"[BuildResult]{e}")

class WorkerThread(QThread):
	def __init__(self, process_single_program, t_id):
		super().__init__()
		self.process_single_program = process_single_program
		self.t_id = t_id
		
	def run(self):
		self.process_single_program(self.t_id)

class Job(QObject):
    task_msg = pyqtSignal(str)
    task_started = pyqtSignal()
    task_finished = pyqtSignal()
    task_fail_result = pyqtSignal()
    task_pass_result = pyqtSignal()

    def __init__(self, job_build, job_cmd, job_ui):
        self.job_build = job_build
        self.job_cmd = job_cmd
        self.ui = job_ui
        self.task_process = None
        self.cmd_result = None

    def run(self):
        try:
            self.task_process = QProcess()
            self.task_process.setProcessChannelMode(QProcess.MergedChannels)

            if platform.system()!= 'Windows':
                env = QProcessEnvironment.systemEnvironment()
                env.insert('PATH', '/usr/bin:'+env.value('PATH'))
                self.task_process.setProcessEnvironment(env)
            self.task_process.readyReadStandardOutput.connect(self.process_output)
            self.task_process.started.connect(self.task_started.emit)

            if platform.system() == 'Windows':
                self.task_process.start('cmd.exe', ['/c', self.job_cmd])
            else:
                self.task_process.start('bash', ['-c', self.job_cmd])

            self.task_process.waitForFinished(-1)
            self.process_output()

        except Exception as e:
            logging.exception(f"[RunJob]{e}")
        finally:
            self.task_process.waitForFinished()
            if self.task_process.exitCode() != 0:
                self.cmd_result = 'Fail'
                self.task_fail_result.emit()
            else:
                self.cmd_result = 'Pass'
                self.task_pass_result.emit()
            self.task_finished.emit()
            self.task_process.close()
            self.deleteLater()

    def process_output(self):
        try:
            while self.task_process.state() == QProcess.Running or self.task_process.bytesAvailable() > 0:
                if self.task_process.canReadLine():
                    realtime_output = self.task_process.readAllStandardOutput().data().decode()
                    lines = realtime_output.splitlines()
                    for line in lines:
                        self.task_msg.emit(f"{str(line)}")
                else:
                    break
        except Exception as e:
            logging.exception(f"[ProcessOutput]{e}")

    def disconnect_singals(self):
        try:
            self.task_msg.disconnect()
            self.task_started.disconnect()
            self.task_pass_result.disconnect()
            self.task_fail_result.disconnect()
            self.task_finished.disconnect()
        except Exception as e:
            logging.exception(f"[DisconnectSingal]{e}")
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
rckstar60
iT邦見習生 ‧ 2024-01-20 01:27:19
【**此則訊息已被站方移除**】

尚未有邦友回答

立即登入回答