Qt释放线程资源的一些工程上的方法

Qt官方文档的方法

QThread创建在栈上,然后QObject需要配合QThread释放资源
直接上代码。结束的时候线程quit and wait

直接上代码

class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    Controller() {
        Worker *worker = new Worker;
        worker->moveToThread(&workerThread);
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);

    ~Controller() {
        workerThread.quit();
        workerThread.wait();
    }

上了关键核心代码。
直接按照顺序来说。

1.观察析构函数

    ~Controller() {
        workerThread.quit();
        workerThread.wait();
    }

一步步来

  • 工作线程quit跟wait退出结束,发出finished信号。

2. 线程退出

        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);

线程退出通知QObject对象删除

3. QThread释放

由于QThread在栈上,所以会自己销毁。

这三部完美的释放了线程资源。

我的做法

我上面讲的第二种方法实际上一开始写的并不好,虽说你把我的代码QObject跟QThraed加上析构函数输出发现也会释放,但是还是会有一些小问题。感谢知乎大佬指出来了。我直接上正确的结论。

工程代码在这里
https://github.com/CryFeiFei/Qt_Teach/tree/master/Qt_Teach/Thread2

我的QThread是放到堆上的。即下面的KThread

直接上我的代码。

    m_workerThread = new KThread();
    WorkThread* worker = new WorkThread();
    worker->moveToThread(m_workerThread);

    //等工作的QObject结束,让线程停止结束
    connect(worker, &WorkThread::workFinished, m_workerThread, [this]()
    {
        m_workerThread->quit();
        m_workerThread->wait();
    });

    //线程停止发给QObject让他自己销毁。
    connect(m_workerThread, &QThread::finished, worker, &WorkThread::deleteLater);

    // QObject销毁之后,让线程自己销毁。
    connect(worker, &WorkThread::destroyed, m_workerThread, &QThread::deleteLater);

解释都在备注上。

对比Qt官方的文档,也就是把QThread申请放到了堆上,然后多了一步释放QThread的操作。

    // QObject销毁之后,让线程自己销毁。
    connect(worker, &WorkThread::destroyed, m_workerThread, &QThread::deleteLater);

有兴趣可以自己下载代码调试下,会发现KThread跟worker的析构函数都完美释放了。

释放线程资源必须要做的(避免死锁

一定要等线程停止之后,再销毁线程

QWaitCondition

一定要等线程停止之后,再销毁线程

生产者消费者是用QWaitCondition来进行同步的。

现在我想手动把这个流程停掉

大概有这么几种情况。

比如生产者生产过快,还在wait,这时候我们的线程需要马上停止。

生产者线程在这里wait

if (listBuffer.size() == bufferSize)
{
    bufferNotFull.wait(&mutex);
}

这时候是没有办法把生产者停掉的,如果强行delete,那就未知了,运气好,不崩溃,运气差,就crash了。

再看看我们的控制代码是在上面这段代码之前的。

while(1)
{
    //xxxxxxx
    if (m_bPause)
    {
        emit workPause();
        continue;
    }
    //..................
    //xxxxx
    if (listBuffer.size() == bufferSize)
    {
        bufferNotFull.wait(&mutex);
    }

    //xxxxxxx
}

也就是这里死锁之后,我们的生产者是永远停不了的。

同理,消费者过快也会出现这个问题。

所以需要我们在释放这种资源的时候要手动调用下两个条件变量的

xxxx.wakeAll();
xxxx.wakeAll();

这样能够避免线程释放资源发生死锁。导致crash。

还有一个方法。

QWaitCondition 的wait是有一个超时时间的,你可以设定一个超时时间,这样就会进入下一次循环,也会避免死锁了。逃)

PS。所有的代码都更新已经放到了github上。公众号的文章发了不能改,以我的代码为准吧。


文章作者: 张小飞
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 张小飞 !
 上一篇
单例模式 单例模式
单例模式单例模式,顾名思义,就是当前Application只有一个实例存在。既然有一个实例,所以我们必须要保证两件事 该类不能有public的构造函数 该类不能够被复制 对于不能够有public的构造函数这种条件,又可以分为两类 只有
2020-07-03
下一篇 
Qt线程同步-单生产者多消费者 Qt线程同步-单生产者多消费者
序单生产者单消费者大家应该已经掌握了。上一篇使用的是QMutex跟QWaitCondition。 如果你的C++编译器版本比较高的话,那就可以使用C++11的 std::condition_variable了 代码这次对比单生产者单消费者,
  目录