线程的互斥和同步(9)- Qt中的读写锁QReadWriteLock

Qt中提供了 QReadWriteLock 类,我们可以方便的使用读写锁。

读写锁 是指 读锁写锁 。 适用于多个线程读操作比较频繁,而写操作不频繁的场景中。
它能够保证多个线程读操作访问资源时同时进行,而写入操作时阻塞读操作。也就是我们常说的, 读共享写独占


1. 读共享和写独占

(1) 读共享
  • 当其他线程占用读锁的时候,如果其他线程请求读锁,会立即获得。
  • 当其他线程占用读锁的时候,如果其他线程请求写锁,会阻塞等待读锁的释放。
(2) 写独占
  • 当其他线程占用写锁的时候,如果其他线程请求读锁,会阻塞等待写锁的释放。
  • 当其他线程占用写锁的时候,如果其他线程请求写锁,会阻塞等待写锁的释放。

2. 读写优先级

Qt的 QReadWriteLock 默认优先级是写优先,即写锁的先级>读锁。
举个例子,比如当线程A占用写锁的时候,线程B请求读锁,阻塞等待;线程C请求写锁,阻塞等待。那么当线程A释放写锁的时候,此时线程C会占用读写锁,因为写的优先级大于读的优先级。

QReadWriteLock 中常用的函数如下:

  • lockForRead() ; 请求读锁
  • lockForWrite() ; 请求写锁
  • tryLockForRead() ; 尝试请求读锁,非阻塞函数,可以设置超时时间。
  • tryLockForWrite() ; 尝试请求写锁,非阻塞函数,可以设置超时时间。
  • unlock() ; 解锁(解读锁和解写锁,均使用该函数)

下面为读写锁的简单使用:

读线程:

class ReadThread : public QThread
{
public:
    void run(void){
        while (1){
            // 读锁
            readWriteLock.lockForRead();
            qDebug() << "Read Thread: " << QThread::currentThreadId() \
                     << ", Number is " << g_number;
            readWriteLock.unlock();

            QThread::msleep(100);
        }
    }
};

写线程:

class WriteThread : public QThread
{
public:
    void run(void){
        while (1) {
            // 写锁
            readWriteLock.lockForWrite();
            g_number++;
            readWriteLock.unlock();

            QThread::msleep(500);
        }
    }
};

调用部分:

// 创建并开启写入线程
WriteThread writeThread;
writeThread.start();

// 创建并开启读线程
ReadThread readThread[5];
for (int i=0; i<5; ++i)
    readThread[i].start();

// 等待线程结束
writeThread.wait();
for (int i=0; i<5; ++i)
    readThread[i].wait();

本例子中, g_number 为一个全局变量,是共享资源;启动5个线程读操作,1个线程写操作。每隔500ms进行一次写操作,每个线程每隔100ms进行一次读操作。

同互斥锁(互斥量)一样,读写锁也可以设置 递归锁非递归锁 。 当设置为 递归锁 时,只有同线程中所有的锁都被解锁,其他的线程才能够获取该锁。
关于 递归锁非递归锁 的介绍, 可以参照: 线程的互斥和同步(8)- C++11中的互斥锁和条件变量

同互斥锁一样,提供了互斥锁的管理类: QMutexLocker ;读写锁也提供了,读锁和写锁的管理类:
QReadLockerQWriteLocker :构造时加锁,析构时解锁。这里就不过多的介绍了。

不会飞的纸飞机
扫一扫二维码,了解我的更多动态。

下一篇文章:Qt中的线程池QThreadPool