• Qt 线程常用同步方式


    Qt  线程(一) Qt 线程(一) Qt 多线程实现的两种方式 线程实现详解_恋恋西风的博客-CSDN博客_qt 跨线程调用

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

    下面说一下主要方式:

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

    1.  互斥量 QMutex

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

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

    mythread.cpp
    1. QMutex mWaitMutex;
    2. void MyThread::run()
    3. {
    4. exitflag = true;
    5. while(exitflag)
    6. {
    7. QMutexLocker locker(&mWaitMutex);
    8. qDebug() << "MyThread thread id:" << QThread::currentThreadId();
    9. sleep(1);
    10. }
    11. }

    2. 条件变量QWaitCondition

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

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

    1. void MyThread::run()
    2. {
    3. exitflag = true;
    4. while(exitflag)
    5. {
    6. QMutexLocker locker(&mWaitMutex);
    7. mWaitStatusCondition.wait(&mWaitMutex,1);
    8. qDebug() << "MyThread thread id:" << QThread::currentThreadId();
    9. sleep(1);
    10. }
    11. }
    12. void MyThread::stop()
    13. {
    14. mWaitStatusCondition.wakeAll();
    15. }

    3. 信号量semaphore

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

    API:

    1. 1)获取n个资源
    2. ​ 调用acquire(n)将尝试获取n个资源。如果没有那么多可用的资源,调用将被阻塞,直到出现可用的资源为止。
    3. void QSemaphore::acquire(int n = 1)
    4. 2)释放n个资源
    5. ​ 调用release(n)函数释放n个资源。
    6. void QSemaphore::release(int n = 1)
    7. 3)获取可用资源的数量
    8. ​ 调用available()函数返回可用资源的数量。
    9. int QSemaphore::available() const
    10. 4)尝试获取n个资源
    11. ​ 调用tryAcquire()函数尝试获取资源,如果不能获取资源,它将立即返回。
    12. bool QSemaphore::tryAcquire(int n = 1)

    使用样例:

    1. const int BufferSize = 12;
    2. QSemaphore freeBytes(BufferSize);
    3. QSemaphore usedBytes;
    4. const int DataSize = 100;
    1. class Producer : public QThread
    2. {
    3. public:
    4. void run() override
    5. {
    6. for (int i = 0; i < DataSize; ++i) {
    7. freeBytes.acquire();
    8. // doing produce
    9. usedBytes.release();
    10. }
    11. }
    12. };
    1. class Consumer : public QThread
    2. {
    3. Q_OBJECT
    4. public:
    5. void run() override
    6. {
    7. for (int i = 0; i < DataSize; ++i) {
    8. usedBytes.acquire();
    9. // doing consume;
    10. freeBytes.release();
    11. }
    12. fprintf(stderr, "\n");
    13. }
    14. };

    main

    1. int main(int argc, char *argv[])
    2. {
    3. QCoreApplication app(argc, argv);
    4. Producer producer;
    5. Consumer consumer;
    6. producer.start();
    7. consumer.start();
    8. producer.wait();
    9. consumer.wait();
    10. return 0;
    11. }

    4. 读写锁

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

    1. void write()
    2. {
    3. QReadLocker locker(&lock);
    4. ..........
    5. }
    6. void read()
    7. {
    8. QWriteLocker locker(&lock);
    9. ..............
    10. }

  • 相关阅读:
    手写数组方法之用于遍历的方法
    动画应用的五个阶段
    27、Java高级特性——集合、ArrayList集合、LinkedList集合、List接口、ArrayList和LinkedList的区别
    2021:Python的下载安装教程(很详细,初学者也能懂)
    一文浅入Springboot+mybatis-plus+actuator+Prometheus+Grafana+Swagger2.9.2开发运维一体化
    从区划边界geojson中查询经纬度坐标对应的省市区县乡镇名称,开源Java工具,内存占用低、高性能
    python多进程
    接口测试神器Apifox究竟有多香?
    【STM32嵌入式系统设计与开发】——15PassiveBeep(无源蜂鸣器应用_GPIO输出状态实现)
    [附源码]java毕业设计校园博客系统
  • 原文地址:https://blog.csdn.net/q610098308/article/details/126246816