千锤百炼出深山, 烈火焚烧若等闲
Emacs
2023-11-05 1823字

最近心情有些沉闷, 因为我的 EAF 项目不断遭遇 QThread: Destroyed while thread is still running 的错误, 当这个问题出现时, 整个 EAF 进程都会崩溃。

复现这个错误也特别让人头疼, 因为它重现过程很随机: 通常在使用文件管理器搜索文件并按下回车键时触发, 但让人困惑的是, 这种错误只在大约 10% 的情况下发生, 而且毫无规律可循。 更加挑战的是, 在调试过程中这个问题从不出现, 却总是在日常使用突然发生。

前前后后修了几个月, 每天下班没事的时候就尝试修复一下, 但是每次当我觉得补丁有希望的时候, 无情的崩溃再次证明自己没有理解这个 Bug 发生的根本原因。

今天早上起床已经没有灵感了, 闲来没事就把相关代码丢给 ChatGPT, 让它帮忙分析一下, 如果分析不对, 也就当作聊天了。

在一番代码解析后, ChatGPT 指出了可能的问题所在:

def start_marker_input_monitor_thread(self, callback_tag):
    self.fetch_marker_input_thread = FetchMarkerInputThread(callback_tag, self.fetch_marker_callback())
    self.fetch_marker_input_thread.match_marker.connect(self.handle_input_response)
    self.fetch_marker_input_thread.start()

def stop_marker_input_monitor_thread(self):
    if self.fetch_marker_input_thread is not None and self.fetch_marker_input_thread.isRunning():
        self.fetch_marker_input_thread.running_flag = False
        self.fetch_marker_input_thread = None

def start_search_input_monitor_thread(self, callback_tag):
    self.fetch_search_input_thread = FetchSearchInputThread(callback_tag)
    self.fetch_search_input_thread.search_changed.connect(self.handle_input_response)
    self.fetch_search_input_thread.search_finish.connect(self.handle_search_finish)
    self.fetch_search_input_thread.start()

def stop_search_input_monitor_thread(self):
    if self.fetch_search_input_thread is not None and self.fetch_search_input_thread.isRunning():
        self.fetch_search_input_thread.stop()
        self.fetch_search_input_thread = None

ChatGPT 认为 fetch_marker_input_threadfetch_search_input_thread 这两个 QThread 对象在设置为 None 之前应该使用 QThread.wait() 来等待 QThread 线程执行完。 强制设置为 None 就会让 Python 把 QThread 对象从 self 对象的引用中去掉, 如果这时垃圾回收运行, 同时 QThread 正在子线程执行, 就会发生多线程竞争条件的 bug, 也是开篇 QThread: Destroyed while thread is still running 错误的原因。

嗯, ChatGPT 说的很有道理, 每个语言的垃圾回收的机制都是根据运行时内存的状态动态决定的, 垃圾回收并没有特定的时机, 这个不就符合我上面说的随机崩溃的现象吗?

在我的代码中加入了 QThread.wait() 代码后, 问题似乎得到了解决, EAF 再也没有出现过崩溃。

结语

当我们在代码和现实社会中遇到问题, 一定不要放弃, 相信总有一天会解决问题的, 而相信这一点的前提时, 要让自己接受一些问题是今天解决不了的。 ;)