QT中线程间的同步分别有QMutex互斥锁、QSemephone信号量、QWaitCondition条件变量和QReadWriteLock读写锁四种方式。
这边来介绍的是读写锁,一般应用与具有大量读操作的场景。
1、读写锁的特性:读共享,写独占。
读共享 :
当其他线程占用读锁的时候,如果其他线程请求读锁,会立即获得。
当其他线程占用读锁的时候,如果其他线程请求写锁,会阻塞等待读锁的释放。
写独占 :
当其他线程占用写锁的时候,如果其他线程请求读锁,会阻塞等待写锁的释放。
当其他线程占用写锁的时候,如果其他线程请求写锁,会阻塞等待写锁的释放。
2、读写优先级
默认优先级是写优先,即写锁的优先级>读锁,哪怕是读先排队的也没用。
3、常用函数包含:
lockForRead() ; 请求读锁
lockForWrite() ; 请求写锁
tryLockForRead() ; 尝试请求读锁,非阻塞函数,可以设置超时时间。
tryLockForWrite() ; 尝试请求写锁,非阻塞函数,可以设置超时时间。
unlock() ; 解锁(解读锁和解写锁,均使用该函数)
4、常关联的类包含:
QReadLocker;
QWriteLocker;
5、例子:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>
#include <QtWidgets>
#include <QThread>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
void delay(int msec);
private slots:
void slotStartThread();
void slotReadControl();
void slotWriteControl();
private:
QPushButton* m_readbtn;
QPushButton* m_writebtn;
QPushButton* m_startthreadbtn;
QReadWriteLock m_readWriteLock;
};
class ReadThread : public QThread
{
Q_OBJECT
public:
ReadThread();
~ReadThread();
void run();
void setReadWriteLock(QReadWriteLock &lock);
private:
QReadWriteLock* m_readWriteLock;
};
class WriteThread : public QThread
{
Q_OBJECT
public:
WriteThread();
~WriteThread();
void run();
void setReadWriteLock(QReadWriteLock &lock);
private:
QReadWriteLock* m_readWriteLock;
};
#endif // WIDGET_H
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->setFixedSize(300,300);
m_readbtn = new QPushButton("读操作",this);
m_writebtn = new QPushButton("写操作",this);
m_startthreadbtn = new QPushButton("开启线程",this);
QVBoxLayout* lay = new QVBoxLayout(this);
lay->addWidget(m_startthreadbtn);
lay->addWidget(m_readbtn);
lay->addWidget(m_writebtn);
this->setLayout(lay);
connect(m_startthreadbtn,SIGNAL(clicked()),this,SLOT(slotStartThread()));
connect(m_readbtn,SIGNAL(clicked()),this,SLOT(slotReadControl()));
connect(m_writebtn,SIGNAL(clicked()),this,SLOT(slotWriteControl()));
}
Widget::~Widget()
{
}
//阻塞延时,用来判断读或者写上锁期间,其它线程的读或者写是否会被阻塞。
void Widget::delay(int msec)
{
QDateTime currentime = QDateTime::currentDateTime();
while (currentime.addMSecs(msec) > QDateTime::currentDateTime())
{
}
}
void Widget::slotStartThread()
{
for (int i = 0; i < 3; ++i)
{
ReadThread* rthread = new ReadThread();
rthread->setReadWriteLock(m_readWriteLock);
rthread->start();
}
WriteThread* wthread = new WriteThread();
wthread->setReadWriteLock(m_readWriteLock);
wthread->start();
}
void Widget::slotReadControl()
{
//测试结果得出,读的时候仍然可以读操作不阻塞,但是读的时候会阻塞写操作。
QReadLocker locker(&m_readWriteLock);
qWarning()<<"main read lock"<<QThread::currentThreadId();
delay(5000);
}
void Widget::slotWriteControl()
{
//测试结果得出,写的时候无论是读操作还是写操作都会被阻塞。写的时候,排队中的写操作优先级最高,无论是不是后排队的。
QWriteLocker locker(&m_readWriteLock);
qWarning()<<"main write lock"<<QThread::currentThreadId();
delay(5000);
}
//------------------------read thread--------------------------
ReadThread::ReadThread()
{
}
ReadThread::~ReadThread()
{
}
void ReadThread::setReadWriteLock(QReadWriteLock& lock)
{
m_readWriteLock = &lock;
}
void ReadThread::run()
{
while(1)
{
m_readWriteLock->lockForRead();
qWarning()<<"read lock"<<QThread::currentThreadId();
m_readWriteLock->unlock();
QThread::sleep(1);
}
}
//------------------------write thread--------------------------
WriteThread::WriteThread()
{
}
WriteThread::~WriteThread()
{
}
void WriteThread::setReadWriteLock(QReadWriteLock& lock)
{
m_readWriteLock = &lock;
}
void WriteThread::run()
{
while(1)
{
m_readWriteLock->lockForWrite();
qWarning()<<"write lock"<<QThread::currentThreadId();
m_readWriteLock->unlock();
QThread::sleep(3);
}
}