QT中线程间的同步分别有QMutex互斥锁、QSemephone信号量、QWaitCondition条件变量和QReadWriteLock读写锁四种方式。
这边来介绍的是读写锁,一般应用与具有大量读操作的场景。
1、读写锁的特性:读共享,写独占。
读共享 :
当其他线程占用读锁的时候,如果其他线程请求读锁,会立即获得。
当其他线程占用读锁的时候,如果其他线程请求写锁,会阻塞等待读锁的释放。
写独占 :
当其他线程占用写锁的时候,如果其他线程请求读锁,会阻塞等待写锁的释放。
当其他线程占用写锁的时候,如果其他线程请求写锁,会阻塞等待写锁的释放。
2、读写优先级
默认优先级是写优先,即写锁的优先级>读锁,哪怕是读先排队的也没用。
3、常用函数包含:
lockForRead() ; 请求读锁
lockForWrite() ; 请求写锁
tryLockForRead() ; 尝试请求读锁,非阻塞函数,可以设置超时时间。
tryLockForWrite() ; 尝试请求写锁,非阻塞函数,可以设置超时时间。
unlock() ; 解锁(解读锁和解写锁,均使用该函数)
4、常关联的类包含:
QReadLocker;
QWriteLocker;
5、例子:
1 #ifndef WIDGET_H
2 #define WIDGET_H
3
4 #include <QWidget>
5 #include <QReadWriteLock>
6 #include <QReadLocker>
7 #include <QWriteLocker>
8 #include <QtWidgets>
9 #include <QThread>
10
11 class Widget : public QWidget
12 {
13 Q_OBJECT
14
15 public:
16 Widget(QWidget *parent = 0);
17 ~Widget();
18 void delay(int msec);
19 private slots:
20 void slotStartThread();
21 void slotReadControl();
22 void slotWriteControl();
23 private:
24 QPushButton* m_readbtn;
25 QPushButton* m_writebtn;
26 QPushButton* m_startthreadbtn;
27 QReadWriteLock m_readWriteLock;
28 };
29
30 class ReadThread : public QThread
31 {
32 Q_OBJECT
33 public:
34 ReadThread();
35 ~ReadThread();
36 void run();
37
38 void setReadWriteLock(QReadWriteLock &lock);
39 private:
40 QReadWriteLock* m_readWriteLock;
41 };
42
43 class WriteThread : public QThread
44 {
45 Q_OBJECT
46 public:
47 WriteThread();
48 ~WriteThread();
49 void run();
50
51 void setReadWriteLock(QReadWriteLock &lock);
52 private:
53 QReadWriteLock* m_readWriteLock;
54 };
55
56 #endif // WIDGET_H
1 #include "widget.h"
2
3 Widget::Widget(QWidget *parent)
4 : QWidget(parent)
5 {
6 this->setFixedSize(300,300);
7
8 m_readbtn = new QPushButton("读操作",this);
9 m_writebtn = new QPushButton("写操作",this);
10 m_startthreadbtn = new QPushButton("开启线程",this);
11
12 QVBoxLayout* lay = new QVBoxLayout(this);
13 lay->addWidget(m_startthreadbtn);
14 lay->addWidget(m_readbtn);
15 lay->addWidget(m_writebtn);
16 this->setLayout(lay);
17
18 connect(m_startthreadbtn,SIGNAL(clicked()),this,SLOT(slotStartThread()));
19 connect(m_readbtn,SIGNAL(clicked()),this,SLOT(slotReadControl()));
20 connect(m_writebtn,SIGNAL(clicked()),this,SLOT(slotWriteControl()));
21
22 }
23
24 Widget::~Widget()
25 {
26 }
27
28 //阻塞延时,用来判断读或者写上锁期间,其它线程的读或者写是否会被阻塞。
29 void Widget::delay(int msec)
30 {
31 QDateTime currentime = QDateTime::currentDateTime();
32 while (currentime.addMSecs(msec) > QDateTime::currentDateTime())
33 {
34 }
35 }
36
37 void Widget::slotStartThread()
38 {
39 for (int i = 0; i < 3; ++i)
40 {
41 ReadThread* rthread = new ReadThread();
42 rthread->setReadWriteLock(m_readWriteLock);
43 rthread->start();
44 }
45
46 WriteThread* wthread = new WriteThread();
47 wthread->setReadWriteLock(m_readWriteLock);
48 wthread->start();
49 }
50
51 void Widget::slotReadControl()
52 {
53 //测试结果得出,读的时候仍然可以读操作不阻塞,但是读的时候会阻塞写操作。
54 QReadLocker locker(&m_readWriteLock);
55 qWarning()<<"main read lock"<<QThread::currentThreadId();
56 delay(5000);
57 }
58
59 void Widget::slotWriteControl()
60 {
61 //测试结果得出,写的时候无论是读操作还是写操作都会被阻塞。写的时候,排队中的写操作优先级最高,无论是不是后排队的。
62 QWriteLocker locker(&m_readWriteLock);
63 qWarning()<<"main write lock"<<QThread::currentThreadId();
64 delay(5000);
65 }
66
67 //------------------------read thread--------------------------
68 ReadThread::ReadThread()
69 {
70
71 }
72
73 ReadThread::~ReadThread()
74 {
75
76 }
77
78 void ReadThread::setReadWriteLock(QReadWriteLock& lock)
79 {
80 m_readWriteLock = &lock;
81 }
82
83 void ReadThread::run()
84 {
85 while(1)
86 {
87 m_readWriteLock->lockForRead();
88 qWarning()<<"read lock"<<QThread::currentThreadId();
89 m_readWriteLock->unlock();
90 QThread::sleep(1);
91 }
92 }
93
94 //------------------------write thread--------------------------
95
96 WriteThread::WriteThread()
97 {
98
99 }
100
101 WriteThread::~WriteThread()
102 {
103
104 }
105
106 void WriteThread::setReadWriteLock(QReadWriteLock& lock)
107 {
108 m_readWriteLock = &lock;
109 }
110
111 void WriteThread::run()
112 {
113 while(1)
114 {
115 m_readWriteLock->lockForWrite();
116 qWarning()<<"write lock"<<QThread::currentThreadId();
117 m_readWriteLock->unlock();
118 QThread::sleep(3);
119 }
120 }