Qt读写锁(QReadWriteLock)的使用、读写锁的验证(含源码+注释)

一、读写锁验证示例图

下图为Qt读写锁的演示及验证,在下图中可以看出两个读取数据的函数会一起调用(代表读写锁支持读取锁线程一起运行),且数据操函数并不会调用;而当数据操作函数调用时,两个数据读取函数也不会调用。由此可知,当读取锁开启时,写入锁不能进入,反之亦然。源码在本文第三节(源码含详细注释)。
在这里插入图片描述
提示:不会使用Qt设计师设计界面的小伙伴点击这里

二、读写锁、QReadWriteLock(个人理解)

当有多个线程使用同一块数据且其中部分线程不会对数据做出改变时(多个线程使用同一个锁)。如果使用QMutex实现,同一时间,只能有一个线程可以运行,这样的话会影响效率。
理论上说,那部分不会对数据做出改变的线程可以同时运行;因此,读写锁出现了,当读取锁开启时并不影响其他使用读取锁的线程,可以一起运行,只是写入锁不能进入;但当写入锁开启时,其他线程就只有等待当前开启写入锁的线程解锁才能运行。

三、源码

3.1 CThread(读写锁使用类)

CThread.h

#ifndef CTHREAD_H
#define CTHREAD_H

#include <QObject>
#include <QThread>
#include <QReadWriteLock>

class CThread : public QThread
{
    Q_OBJECT
public:
    explicit CThread(QObject *parent = nullptr);
    ~CThread();

    void run();

    void setFlag(char flag);

    void readFunc1();   //读取操作1函数

    void readFunc2();   //读取操作2函数

    void writeFunc();   //数据操作函数

private:
    static QReadWriteLock *m_sLock;   //定义静态读写锁(方便所有当前线程类对象使用)

    char        m_flag;         //定义char变量存储当前线程的字符

};

#endif // CTHREAD_H

CThread.cpp

#include "CThread.h"
#include <QDebug>
#include <QDateTime>

QReadWriteLock * CThread::m_sLock = new QReadWriteLock; //为静态变量new出对象

CThread::CThread(QObject *parent)
    : QThread(parent)
{
}

CThread::~CThread()
{
}

void CThread::run()
{
    int i = 0;
    //循环输出当前标识符4次
    while(i++ != 4)
    {
        if(0 == m_flag)
        {
            //写入锁上锁
            m_sLock->lockForWrite();
            writeFunc();    //数据操作的内容
            m_sLock->unlock();  //解锁
        }
        else if(1 == m_flag)
        {
            //读取锁上锁
            m_sLock->lockForRead();
            readFunc1();    //数据读取的内容
            m_sLock->unlock();  //解锁
        }
        else
        {
            //读取锁上锁
            m_sLock->lockForRead();
            readFunc2();    //数据读取的内容
            m_sLock->unlock();  //解锁
        }
    }
    qDebug() << "标识符为:" << (int)m_flag << "的线程循环结束";
}

void CThread::setFlag(char flag)
{
    m_flag = flag;
}

//读取操作1
void CThread::readFunc1()
{
    qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss")
             << "readFunc1函数运行,开始睡眠一秒";
    QThread::sleep(1);
    qDebug() << "           readFunc1函数睡眠结束";
}

//读取操作2
void CThread::readFunc2()
{
    qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss")
             << "readFunc2函数运行,开始睡眠一秒";
    QThread::sleep(1);
    qDebug() << "           readFunc2函数睡眠结束";
}

//数据操作
void CThread::writeFunc()
{
    qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss")
             << "writeFunc运行,开始睡眠三秒";
    QThread::sleep(2);
    qDebug() << "           writeFunc睡眠结束";
}

3.2 CMainWindow(线程调用类)

CMainWindow.h

#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H

#include <QMainWindow>
#include "CThread.h"

namespace Ui {
class CMainWindow;
}

class CMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit CMainWindow(QWidget *parent = 0);
    ~CMainWindow();

private slots:
    void on_startBtn_clicked();         //按钮槽函数(启动所有线程)

private:
    Ui::CMainWindow *   ui;

    QList<CThread *>    m_threadList;   //线程指针容器

};

#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"
#include "ui_CMainWindow.h"

CMainWindow::CMainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CMainWindow)
{
    ui->setupUi(this);

    //使用循环为线程链表添加三个线程
    for(int index = 0; index != 3; ++index)
    {
        m_threadList.append(new CThread);
        m_threadList[index]->setFlag(index);   //设置标识符
    }

}

CMainWindow::~CMainWindow()
{
    //循环退出线程并释放
    foreach (CThread *thread, m_threadList)
    {
        thread->quit();
        thread->wait(1);
        delete thread;
    }
    delete ui;
}


void CMainWindow::on_startBtn_clicked()
{
    //启动三个线程
    for(int index = 0; index != 3; ++index)
    {
        m_threadList[index]->start(); //启动线程
    }
}

总结

读写锁允许读取锁线程一起运行,但当写入锁线程运行时则不允许其他线程进入。而且写入锁优先级比读取锁高,当同一时间读取锁和写入锁排队时,写入锁有更大概率运行。读写锁适用于有较多的读取操作,并且在这种情况相对于QMutex有更大的优势,并且读取锁有类似于QMutexLocker的类。

相关文章

启动QThread线程的两种方法(含源码+注释)
Qt互斥锁(QMutex)、条件变量(QWaitCondition)讲解+QMutex实现多线程循环输出ABC(含源码+注释)
Qt互斥锁(QMutex)的使用、QMutexLocker的使用(含源码+注释)
QSemaphore的使用+QSemaphore实现循环输出ABC(含源码+注释)
QRunnable线程、QThreadPool(线程池)的使用(含源码+注释)
Qt读写锁(QWriteLocker、QReadLocker)的理解和使用(含部分源码)
Qt之线程运行指定函数(含源码+注释,优化速率)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

  • 12
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lw向北.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值