一、读写锁验证示例图
下图为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();
void readFunc2();
void writeFunc();
private:
static QReadWriteLock *m_sLock;
char m_flag;
};
#endif
CThread.cpp
#include "CThread.h"
#include <QDebug>
#include <QDateTime>
QReadWriteLock * CThread::m_sLock = new QReadWriteLock;
CThread::CThread(QObject *parent)
: QThread(parent)
{
}
CThread::~CThread()
{
}
void CThread::run()
{
int i = 0;
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;
}
void CThread::readFunc1()
{
qDebug() << QDateTime::currentDateTime().toString("hh:mm:ss")
<< "readFunc1函数运行,开始睡眠一秒";
QThread::sleep(1);
qDebug() << " readFunc1函数睡眠结束";
}
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.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^/)
注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。 注:如有侵权,请联系作者删除
|