You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Qt智能指针与deleteLater时,如何修复线程内存泄漏?

问题描述

我有一个WorkerThreadManager类,用于创建并管理多个Qt线程,代码如下:

class WorkerThread : public QThread
{
    Q_OBJECT
public:
    WorkerThread() : QThread()
    {
        start();
    }

    virtual ~SearchCacheWorkerThread()
    {
        quit();
        wait();
    }
    
    virtual void run() Q_DECL_OVERRIDE
    {
        // 从mysql获取数据
        // 处理结果
        // 向results_中添加大量新项
    
        quit();
    }

private:
    QList<int> results_;
};
typedef QSharedPointer<WorkerThread> WorkerThreadPtr;

class WorkerThreadManager : QObject
{
    Q_OBJECT
public:
    WorkerThreadManager(const int numThreads) : QObject()
    {
        for ( int i = 0; i < numThreads; ++i )
        {
            threads_ << WorkerThreadPtr( new WorkerThread(), &QObject::deleteLater );
        }
    }
    virtual ~WorkerThreadManager() {}

private:
    QList<WorkerThreadPtr> threads_;

当销毁WorkerThreadManager对象时,我发现内存并未被释放。我了解到,如果线程已退出事件循环,deleteLater将不会生效,因此移除了所有quit()调用以确保线程在deleteLater调用前保持在事件循环中,但仍存在内存泄漏。

请问:

  1. 如何正确销毁这些线程(最好使用智能指针)?
  2. 如何确保即使调用了析构函数,线程也会在销毁前完成任务?
解决方案

1. 正确销毁线程(结合智能指针)

你的代码存在两个核心问题:一是WorkerThread的析构函数名错误(写成了~SearchCacheWorkerThread()),导致析构逻辑完全没被执行;二是用QSharedPointer搭配deleteLater的方式不适合QThread,因为deleteLater依赖事件循环,线程提前退出后该机制会失效。

修正后的实现如下:

class WorkerThread : public QThread
{
    Q_OBJECT
public:
    WorkerThread() : QThread()
    {
        start();
    }

    // 修正析构函数名,确保逻辑被执行
    virtual ~WorkerThread() override
    {
        // 先请求中断任务,再退出事件循环,最后等待线程结束
        requestInterruption();
        quit();
        wait();
    }
    
    virtual void run() override
    {
        while (!isInterruptionRequested()) {
            // 从mysql获取数据
            // 处理结果
            // 向results_中添加大量新项

            // 如果是一次性任务,处理完成后退出循环
            break;
        }
        // 移除run()中的quit(),交给析构函数统一管理线程退出
    }

private:
    QList<int> results_;
};

// 直接使用QSharedPointer,无需指定deleteLater,析构函数会自行处理线程停止
typedef QSharedPointer<WorkerThread> WorkerThreadPtr;

class WorkerThreadManager : QObject
{
    Q_OBJECT
public:
    WorkerThreadManager(const int numThreads) : QObject()
    {
        for ( int i = 0; i < numThreads; ++i )
        {
            threads_ << WorkerThreadPtr( new WorkerThread() );
        }
    }

    virtual ~WorkerThreadManager() override
    {
        // 智能指针会自动调用WorkerThread的析构函数,无需手动销毁
        threads_.clear();
    }

private:
    QList<WorkerThreadPtr> threads_;
};

关键要点:

  • 修正析构函数名,确保线程停止逻辑被触发;
  • 在析构函数中通过requestInterruption()、quit()、wait()三步完成线程的安全停止与资源回收;
  • 移除run()中的quit(),让线程生命周期由析构函数控制,避免线程提前退出导致deleteLater失效;
  • QSharedPointer会在管理器销毁时自动释放WorkerThread对象,触发其析构函数完成线程清理。

2. 确保线程完成任务后再销毁

要保证线程在销毁前完成当前任务,需要在线程的run()方法中分步检查中断请求,仅在当前步骤完成后再响应中断:

void WorkerThread::run() override
{
    while (!isInterruptionRequested()) {
        bool taskCompleted = true;

        // 步骤1:从mysql获取数据
        if (!isInterruptionRequested()) {
            // 执行获取逻辑
        } else {
            taskCompleted = false;
        }

        // 步骤2:处理结果
        if (taskCompleted && !isInterruptionRequested()) {
            // 执行处理逻辑
        } else {
            taskCompleted = false;
        }

        // 步骤3:添加结果到列表
        if (taskCompleted && !isInterruptionRequested()) {
            // 执行添加逻辑
        }

        // 一次性任务完成后退出循环
        break;
    }
}

同时保持WorkerThread析构函数中的逻辑:通过requestInterruption()发出中断请求,而非强制终止线程,让线程自行完成当前正在执行的步骤后再退出,最后通过wait()等待线程完全结束,确保任务完整性与线程销毁的安全性。

内容的提问来源于stack exchange,提问作者A. Paschos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:32:38