各位大大好
最近在嘗試切換不同系統下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}")