为了更高效的处理hex文件与ui界面间的关系,将hex处理扔到了线程池中去操作,只是没想到这半吊子的水平处理不好线程池间的关系,导致卡住了两天。
为什么会卡住我两天
起因是在创建一个解析hex线程之后,将任务移到线程池。只是hex的解析并不是一次性,可能有多个hex需要加载,这就导致了问题的出现—多次加载hex都是把同一个对象多次提交给了线程池,还设置了线程池自动管理任务,这就导致线程池每次执行完任务后会自动销毁对象,再次提交任务对象时,this指向变成了野指针。如下面的代码:
void MainWindow::HexpressTaskThread()
{
    // 创建解析器和线程
    m_hexParser = new HexParser();
    // 连接信号槽
    connect(this, &MainWindow::sendhexdata, this, [this](const QByteArray &data) {
        m_hexParser->setHexData(data);
        QThreadPool::globalInstance()->start(m_hexParser);
    });
    connect(m_hexParser, &HexParser::parseFinished,
            this, &MainWindow::onHexDataParsed, Qt::QueuedConnection);
    connect(m_hexParser, &HexParser::parseError,
        this, [this](const QString &err){
            QMessageBox::warning(this, "Error", err);
        }, Qt::QueuedConnection);
}把同一个 HexParser 对象重复地提交给了 QThreadPool,而 QThreadPool 默认会在 run() 执行完后自动销毁(auto-delete)这个 QRunnable 对象。第二次再去调用 setHexData 时,this 其实已经是野指针,从而导致了进程崩溃,程序崩溃。
原因拆解
QThreadPool 默认的行为
 HexParser 同时继承了 QObject 和 QRunnable(或至少实现了 QRunnable 的接口),并且没有显式关闭自动删除,那么在第一次调用QThreadPool::globalInstance()->start(m_hexParser);并且 run() 方法结束后,QThreadPool 会自动 delete this,导致原来的 HexParser 对象指针失效。
第二次加载文件时继续使用失效对象
在 HexpressTaskThread() 里:
connect(this, &MainWindow::sendhexdata, this, [this](const QByteArray &data) {
    m_hexParser->setHexData(data);
    QThreadPool::globalInstance()->start(m_hexParser);
});当第二次加载文件再次触发 sendhexdata 信号后,就会对一个已经被销毁了的对象再去 setHexData,从而导致了进程崩溃。
如何修复
动态创建HexParser实例:每次接收到sendhexdata信号时,动态创建一个新的HexParser对象,而非复用同一个对象。
调整信号连接逻辑:将信号槽连接移动到动态对象创建处,确保每个实例独立管理。
void MainWindow::HexpressTaskThread()
{
    // 移除预先创建的m_hexParser,改为在信号触发时动态创建
    connect(this, &MainWindow::sendhexdata, this, [this](const QByteArray &data) {
        // 每次创建新的HexParser实例
        HexParser* hexParser = new HexParser();
        hexParser->setHexData(data);
        // 连接信号槽(需捕获hexParser指针)
        connect(hexParser, &HexParser::parseFinished,
                this, &MainWindow::onHexDataParsed, Qt::QueuedConnection);
        connect(hexParser, &HexParser::parseError,
                this, [this](const QString &err) {
                    QMessageBox::warning(this, "Error", err);
                }, Qt::QueuedConnection);
        // 提交任务到线程池
        QThreadPool::globalInstance()->start(hexParser);
    });
}实际上也可以这样:设置 setAutoDelete(false) 并手动管理;或者改用传统 QThread + moveToThread 的方式来做异步解析。只要别二次使用一个已经被销毁的对象,就不会再崩溃了。





