QT5.14.2 官方例子 - Qt Core 1: Semaphores Example(多信号)

一.系列总链接:

QT5.14.2 官方例子 - 学习系列

https://blog.csdn.net/qq_22122811/article/details/108007519

 

二.项目位置:

Examples\Qt-5.14.2\corelib\threads\semaphores

注:在Examples下的路径

项目模块:corelib\threads

2.1: 资源下载:

渠道1:

下载qtcreator源码,会附带该例程;

渠道2:

github下载链接:

https://github.com/peterwei24/QT5.14.2_Examples/tree/master/allExamplesCode/corelib/threads/semaphores

 

三.项目描述:

演示了生产者往缓存中写入数据,通过信号量保持消费者读取数据的同时性。

项目效果:

这个是官方例子的显示结果,不太方便明白过程,我修改了一下,显示结果如下:

大致能看到过程是围绕着生产者生产完,消费者开始消费的过程,这就符合通过信号量来保持线程间互斥性的设计;

 

四.官网讲解:

https://doc.qt.io/qt-5.14/qtcore-threads-semaphores-example.html

 

演示了使用Qt的多线程编程。

生产者将数据写入缓冲区,直到它到达缓冲区的末尾,然后从头开始重新启动,覆盖现有的数据。消费者线程在生成数据时读取数据并将其写入标准错误。

信号量使它可能拥有比互斥锁更高级别的并发性。如果对缓冲区的访问是由QMutex保护的,那么消费者线程不能与产生线程同时访问缓冲区。不过,让两个线程同时处理缓冲区的不同部分也没有什么坏处。

该示例包含两个类:生产者和消费者。两者都继承自QThread。用于这两个类之间通信的循环缓冲区和保护它的信号量是全局变量。

使用QSemaphore来解决生产者-消费者问题的另一种方法是使用QWaitCondition和QMutex。这就是等待条件示例所做的事情。

 

五.思路及逻辑解析:

(对例子进行了部分修改,方便阅读和理解,和项目描述中修改结果一致!)

全局变量:

const int DataSize = 10;

const int BufferSize = 3;
char buffer[BufferSize];

QSemaphore freeBytes(BufferSize);
QSemaphore usedBytes;

DataSize是生产者将生成的数据量。为了使这个例子尽可能简单,我们把它设为常数。BufferSize是循环缓冲区的大小。它小于DataSize,这意味着在某个时间点,生产者将到达缓冲区的末尾,并从开始重新开始。

为了同步生产者和消费者,我们需要两个信号量。freeBytes信号量控制缓冲区的“空闲”区域(生产者还没有填充数据或者消费者已经读取的区域)。usedBytes信号量控制缓冲区的“已使用”区域(生产者已经填充但消费者还没有读取的区域)。

这些信号量一起确保生产者永远不会超过消费者之前的BufferSize字节,并且消费者永远不会读取生产者还没有生成的数据。

freeBytes信号量是用BufferSize初始化的,因为最初整个缓冲区是空的。usedBytes信号量初始化为0(如果没有指定,则为默认值)。

 

生产者类:

class Producer : public QThread
{
public:
    void run() override
    {
        for (int i = 0; i < DataSize; ++i) {
            // 当前信号量是否有可以填充数据的缓冲区,如果资源计数为0,则没有可以填充的缓冲区,
            //     那么该函数会阻塞当前线程
            freeBytes.acquire();
            buffer[i % BufferSize] = "ACGT"[QRandomGenerator::global()->bounded(4)];
            // 使useSpace对象的资源计数加1,此时消费者线程就有机会取数据了
            usedBytes.release();
        }
    }
};

生产者生成数据的DataSize字节。在将一个字节写入循环缓冲区之前,它必须使用freeBytes信号量获得一个“空闲”字节。如果消费者没有跟上生产者的进度,QSemaphore::acquire()调用可能会阻塞。(即消费没跟上,生产就会一定时间后停滞!)

最后,生产者使用usedBytes信号量释放一个字节。已成功地将“空闲”字节转换为“已使用”字节,准备由使用者读取。

补充:

参照:https://blog.csdn.net/hitzsf/article/details/109105288

1.QRandomGenerator: 允许从高质量随机数生成器获取随机值。

QRandomGenerator :: global()返回QRandomGenerator的全局实例,Qt将确保该实例被安全地播种。

  • quint32 bounded(quint32 highest)

    生成[0,hightest) 范围内的quint32 类型的随机的整数

2.void QSemaphore::acquire(int n = 1):试图获取由信号量保护的n个资源。如果n > available(),这个调用将阻塞,直到有足够的资源可用。

3.void QSemaphore::release(int n = 1):释放由信号量保护的n个资源。这个函数也可以用来“创建”资源。例如:

 

消费者类:

class Consumer : public QThread
{
    Q_OBJECT
public:
    void run() override
    {
        for (int i = 0; i < DataSize; ++i) {
            // 当前信号量是否有可以取数据的缓冲区,如果资源计数为0,则没有可取的缓冲区,那么该函数            
            //     会阻塞当前线程
            usedBytes.acquire();
            fprintf(stderr, "%c", buffer[i % BufferSize]);
            // 使freeSpace对象的资源计数加1,此时生产者线程就有机会生产数据了
            freeBytes.release();
        }
        fprintf(stderr, "\n");
    }
};

代码与生产者非常相似,除了这一次我们获得一个“已使用”字节并释放一个“空闲”字节,而不是相反。

main()函数:

在main()中,我们创建了两个线程,并调用QThread::wait()来确保在我们退出之前两个线程都有时间完成:

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

六.知识巩固

https://www.cnblogs.com/alinh/p/6905221.html

信号量的理解

信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里)。而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源。比如对全局变量的访问,有时要加锁,操作完了,在解锁。有的时候锁和信号量会同时使用的
也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后再进行自己下面的步骤,这个任务 并不一定是锁定某一资源,还可以是进行一些计算或者数据处理之类。而线程互斥量则是“锁住某一资源”的概念,在锁定期间内,其他线程无法对被保护的数据进 行操作。在有些情况下两者可以互换。

互斥量和信号量的区别

1. 互斥量用于线程的互斥,信号量用于线程的同步。

这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

2. 互斥量值只能为0/1,信号量值可以为非负整数。(这个似乎不太好理解,信号量实现多个同类资源的多线程互斥和同步)

也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。

3. 互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Command line: -prefix /home/liuyh/workspace/qt5.14.2-arm -opensource -confirm-license -release -strip -shared -xplatform linux-arm-gnueabi-g++ -optimized-qmake -c++std c++11 --rpath=no -pch -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcanvas3d -skip qtconnectivity -skip qtdatavis3d -skip qtdoc -skip qtgamepad -skip qtlocation -skip qtmacextras -skip qtnetworkauth -skip qtpurchasing -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtspeech -skip qtsvg -skip qttools -skip qttranslations -skip qtwayland -skip qtwebengine -skip qtwebview -skip qtwinextras -skip qtx11extras -skip qtxmlpatterns -make libs -make examples -nomake tools -nomake tests -gui -widgets -dbus-runtime --glib=no --iconv=no --pcre=qt --zlib=qt -no-openssl --freetype=qt --harfbuzz=qt -no-opengl -linuxfb --xcb=no -tslib --libpng=qt --libjpeg=qt --sqlite=qt -plugin-sql-sqlite -I/opt/tslib/include -L/opt/tslib/lib -recheck-all executing config test machineTuple + arm-linux-gnueabi-g++ -dumpmachine > sh: 1: arm-linux-gnueabi-g++: not found test config.qtbase.tests.machineTuple FAILED executing config test verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/bin/qmake "CONFIG -= qt debug_and_release app_bundle lib_bundle" "CONFIG += shared warn_off console single_arch" 'QMAKE_LIBDIR += /opt/tslib/lib' 'INCLUDEPATH += /opt/tslib/include' -early "CONFIG += cross_compile" /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec + cd /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/config.tests/verifyspec && MAKEFLAGS= /usr/bin/make clean && MAKEFLAGS= /usr/bin/make > rm -f verifyspec.o > rm -f *~ core *.core > arm-linux-gnueabi-g++ -c -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -O2 -march=armv7-a -mtune=cortex-a7 -mfpu=neon -mfloat-abi=hard -pipe -O2 -w -fPIC -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec -I. -I/opt/tslib/include -I/home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/mkspecs/linux-arm-gnueabi-g++ -o verifyspec.o /home/liuyh/workspace/QT5.14.2/qt-everywhere-src-5.14.2/qtbase/config.tests/verifyspec/verifyspec.cpp > make:arm-linux-gnueabi-g++:命令未找到 > make: *** [Makefile:172:verifyspec.o] 错误 127
06-09

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值