当前位置:网站首页>Qt 线程常用同步方式

Qt 线程常用同步方式

2022-08-10 03:26:00 恋恋西风

多个线程同时访问共享数据时可能会冲突,出现意料之外的结果,这源于操作的原子性问题;为了保证,数据的正确性和完成性,就需要用到数据同步,Qt给我们提供了多种同步方式,

下面说一下主要方式:

互斥锁QMute
条件变量QWaitCondition
信号量QSemaphore
读写锁QReadLocker、QWriteLocker、QReadWriteLock

1.  互斥量 QMutex

我们一般使用 QMutexLocker 对于当前的范围,进行锁住,当离开范围时,自动解锁。

值得注意的是,需要在两个线程中使用同一个锁,然后才能起到锁的作用,主要是为了防止多线程对单个数据的同时操作。 在单线程中,对于锁而言,是没有任何意义的。

mythread.cpp
QMutex mWaitMutex;

void MyThread::run()
{
    exitflag = true;
    while(exitflag)
    {
        QMutexLocker locker(&mWaitMutex);
        qDebug() << "MyThread thread id:" << QThread::currentThreadId();
        sleep(1);
    }
}

2. 条件变量QWaitCondition

注意这个要和 QMutex 一起配合使用;

使用场景:线程A需要等某个条件成立才能继续往下执行,比如 生产者,消费者

void MyThread::run()
{
    exitflag = true;
    while(exitflag)
    {
        QMutexLocker locker(&mWaitMutex);
        mWaitStatusCondition.wait(&mWaitMutex,1);
        qDebug() << "MyThread thread id:" << QThread::currentThreadId();
        sleep(1);
    }
}

void MyThread::stop()
{
   mWaitStatusCondition.wakeAll();
}

3. 信号量semaphore

这是一种提供计数的信号量,所以在消费者与生产者模型中,就变得十分的好用。如果缓存被消费者还没有读取的数据填满,acquire()的调用就会阻塞,直到消费者已经开始消耗这些数据;

API:

(1)获取n个资源

​ 调用acquire(n)将尝试获取n个资源。如果没有那么多可用的资源,调用将被阻塞,直到出现可用的资源为止。

void QSemaphore::acquire(int n = 1)

(2)释放n个资源

​ 调用release(n)函数释放n个资源。

void QSemaphore::release(int n = 1)

(3)获取可用资源的数量

​ 调用available()函数返回可用资源的数量。

int QSemaphore::available() const

(4)尝试获取n个资源

​ 调用tryAcquire()函数尝试获取资源,如果不能获取资源,它将立即返回。

bool QSemaphore::tryAcquire(int n = 1)
 

使用样例:

const int BufferSize = 12;
QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;
const int DataSize = 100;
class Producer : public QThread
{
public:
    void run() override
    {
        for (int i = 0; i < DataSize; ++i) {
            freeBytes.acquire();
           
           // doing produce
            usedBytes.release();
        }
    }
};
 class Consumer : public QThread
{
    Q_OBJECT
public:
    void run() override
    {
        for (int i = 0; i < DataSize; ++i) {
            usedBytes.acquire();
             // doing consume;
            freeBytes.release();
        }
        fprintf(stderr, "\n");
    }
};

main

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    Producer producer;
    Consumer consumer;
    producer.start();
    consumer.start();
    producer.wait();
    consumer.wait();
    return 0;
}

4. 读写锁

前两种保护互斥量的方法比较绝对,其达到的效果是:不管我要对互斥量做些是什么,我都要一个人霸占着,即使我只是看看它,也不能让别人看。这会使得这个互斥量资源的使用率大大下降,造成资源等待等问题。

void write()
{
QReadLocker locker(&lock);
..........
}
 
void read()
{
QWriteLocker locker(&lock);
..............
}

原网站

版权声明
本文为[恋恋西风]所创,转载请带上原文链接,感谢
https://blog.csdn.net/q610098308/article/details/126246816