IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> Qt读写锁(QReadWriteLock)的使用、读写锁的验证(含源码+注释) -> 正文阅读

[C++知识库]Qt读写锁(QReadWriteLock)的使用、读写锁的验证(含源码+注释)

一、读写锁验证示例图

下图为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)的理解和使用(含部分源码)

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

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

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-31 23:45:54  更:2022-03-31 23:48:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:39:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码