Qt多线程问题1

工作过程中用到了Qt的多线程,本来实现了一个发送接收数据的线程,为了排查一些问题而复习了一下Qt锁的一些知识。

假设用一个管理类Manager,里边管理了一个数据接收线程,同时封装了一个saveData的接口:

#ifndef TMPTHREAD_H
#define TMPTHREAD_H

#include <QDebug>
#include <QThread>
#include <QMutex>
#include <QQueue>
#include <QMutexLocker>

class TMPThread: public QThread
{
public:
    TMPThread();

    void saveData(int i);

    void printData();

protected:
    void run() override;

private:
    int             _data;
    QMutex          _mutex;
    QQueue<int>     _data_queue;
};

#endif // TMPTHREAD_H

其中,_data是一个临时记录的数据,_mutex是锁,_data_queue是数据接收队列,具体实现如下:

#include "TMPThread.h"

TMPThread::TMPThread()
    : _mutex(QMutex::NonRecursive)     //  <----------- 1
{

}

void TMPThread::saveData(int i)
{
    QMutexLocker lock(&_mutex);
    _data_queue.enqueue(i);

    if(!this->isRunning() && !_data_queue.isEmpty()){
        this->start();
        // this->printData();          //  <--------------- 2
    }
}

void TMPThread::printData()
{
    while(!_data_queue.isEmpty()){
        QMutexLocker lock(&_mutex);

        QThread::sleep(1);

        auto data = _data_queue.dequeue();
        qDebug() << "Curr data: " << QString::number(data);
        qDebug() << "Curr queue length: " << QString::number(_data_queue.size());
        lock.unlock();
    }
}

void TMPThread::run()
{
    while(!_data_queue.isEmpty()){
        QMutexLocker lock(&_mutex);

        QThread::sleep(1);

        auto data = _data_queue.dequeue();
        qDebug() << "Curr data: " << QString::number(data);
        qDebug() << "Curr queue length: " << QString::number(_data_queue.size());
        lock.unlock();
    }
}

在1处,可以选择声明锁的类型,Qt默认是递归锁,这里选择手动声明为非递归锁,为了验证问题。重新写了run函数后,实验时发现如果选择this->start()启动,不论锁的类型是什么,都不会死锁,同时也说明了start并非按照自己理解的那样工作,但是如果重新写了printData函数,相当于递归调用了,那么会造成死锁了。

数据管理类实现:

#ifndef MANAGER_H
#define MANAGER_H

#include <QDebug>
#include <QScopedPointer>
#include "TMPThread.h"

class Manager
{
public:
    Manager();
    ~Manager();
    void startAllThreads();

private:
    QScopedPointer<TMPThread>     _thread;
    QScopedPointer<QByteArray>    _buffer1;
    QScopedPointer<QByteArray>    _buffer2;
};

#endif // MANAGER_H

这里在模拟一个双缓冲,后续重新考虑实现,现有的具体实现如下:

#include "Manager.h"


Manager::Manager()
    : _thread(new TMPThread)
    , _buffer1(new QByteArray)
    , _buffer2(new QByteArray)
{

}

Manager::~Manager()
{
    qDebug() << "Delete Manager!";
}

void Manager::startAllThreads()
{
    qDebug() << "Manger: Start Save Data!";

    for(int i = 0; i < 10; i++){
        _thread->saveData(i);
    }
}

在主函数引用Manager,并且调用实验:

#include <QCoreApplication>
#include <QThread>
#include <QScopedPointer>
#include "Manager.h"

int main(int argc, char *argv[])
{
    QScopedPointer<Manager> manager{new Manager};
    manager->startAllThreads();

    QThread::sleep(20);
    qDebug() << "Finished!";
    return 0;
}

以上就是问题的一些发现。

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值