QT 线程之QSemaphore(深入理解)

前言:

转载请附上连接,本帖原创请勿照抄。

QSemaphore也可以被用来使线程的执行顺序化,和QMutex的方法相似。信号量和互斥量的不同在于,信号量可以在同一时间被多于一个的线程访问。

在博文中通常将QSemaphore具体使用定义为 生产者/消费者 模式,作者觉得这样子定义可以将的更详细、明白,理解也更容易理解一些。

详解QSemaphore 线程同步过程中,有两个栗子在这里给大家举一下,看完本文更深入的了解生产者/消费者。

栗子 一 、生产者/消费者 模式对应的关系,以及实现。

栗子 二 、生产者/消费者 模式一个生产者多个消费者的具体实现以及对应关系。

QT线程之QSemaphore(深入理解)目录

项目结构:

栗子 一、 QSemaphore 线程同步 生产者/消费者

    调用实现

    初始化全局变量

    实现生产者线程

    实现消费者线程

栗子 二、 QSemaphore 线程同步 一个生产者多个消费者

    调用实现

    初始化全局变量

    实现生产者线程

    实现消费者线程

    运行截图:

遇到的问题 1

遇到的问题 2

遇到的问题 3


项目结构:

mainwindow 是界面UI实现文件

mythread 是线程实现文件

这是基本实现线程的一篇博客可以忽略 QT线程简单实现 

栗子 一、 QSemaphore 线程同步 生产者/消费者

    调用实现

    先上次要代码,调用代码。

//引入头文件
#include "mythread.h"

//赋值
mythread *thread;
WriterThread *consumer;
Consumer *writer;

//调用
void MainWindow::on_pushButton_2_clicked()
{

    thread->start();
    consumer->start();
    thread->wait();
    consumer->wait();
}

    初始化全局变量

const int DataSize = 10;
const int BufferSize = 2;
char buffer[BufferSize];

QSemaphore freeSpace(BufferSize);
QSemaphore usedSpace(0);

    实现生产者线程

     for (int i = 0; i < DataSize; ++i) {

         freeSpace.acquire();
         qDebug() << "生产:thread ";
         usedSpace.release();

     }

    实现消费者线程

    for (int i = 0; i < DataSize; ++i) {
        //freeSpace.release();
        usedSpace.acquire();
        qDebug() << "消费:thread ";


    }

栗子 二、 QSemaphore 线程同步 一个生产者多个消费者

    调用实现

    先上次要代码,调用代码。

//引入头文件
#include "mythread.h"

//赋值
mythread *thread;
WriterThread *consumer;
Consumer *writer;

//调用
void MainWindow::on_pushButton_2_clicked()
{

    thread->start();
    consumer->start();
    thread->wait();
    consumer->wait();
}

    在这里需要注意一个问题,个人觉得需要注意一下:

    那就是在停止线程前先执行thread->quit()停止线程,先停止线程在结束线程,否则很有可能在你wait结束完线程之后你的线程还会跑一会。

 

    初始化全局变量

//互斥锁
QMutex mutex;                

//单个生产者消费者使用变量
const int DataSize = 60;
const int BufferSize = 10;
//char buffer[BufferSize];

//产品数量
QSemaphore freeSpace(BufferSize);
QSemaphore usedSpace(0);

//缓冲区可以放10个产品
int buffer[10];               
int numtaken=60;
int takei=0;

    实现生产者线程

void mythread::run()
{
    for (int i = 0; i < DataSize; ++i)
    {
        freeSpace.acquire();
        qDebug() << "生产:thread "<<QThread::currentThreadId();
        usedSpace.release();

        //暂停一下 不然闪屏太快
        //已经500度的眼睛了,近视加散光别在老花眼
        sleep(1);
    }
}

    实现消费者线程

void WriterThread::run()
{
    //函数获取当前进程的ID
    while(numtaken>1)
    {
        usedSpace.acquire();   //P(s2)操作原语
        mutex.lock();        //从缓冲区取出一个产品...多个消费者,不能同时取出,故用了互斥锁
        printf("thread %ul take %d from buffer[%d] \n",currentThreadId(),buffer[takei%10],takei%10);

        qDebug() << "消费:thread "<<QThread::currentThreadId()<<"take "+QString::number(takei%10)+" from buffer["+QString::number(buffer[takei%10])+"] \n";

        takei++;
        numtaken--;
        mutex.unlock();
        usedSpace.release();   //V(s1)操作原语
        //sleep(1);
    }
}

QMutex类提供的是线程之间的访问顺序化。
QMutex的目的是保护一段代码,使得同一时间只有一个线程可以访问它。但在一个线程中调用lock(),其它线程将会在同一地点试图调用lock()时会被阻塞,直到这个线程调用unlock()之后其它线程才会获得这个锁。

信号量QSemaphore可以理解为对互斥量QMutex功能的扩展,互斥量只能锁定一次而信号量可以获取多次,它可以用来保护一定数量的同种资源。acquire()函数用于获取n个资源,当没有足够的资源时调用者将被阻塞直到有足够的可用资源。release(n)函数用于释放n个资源。

    运行截图:

    因为把sleep注释了,所以可以看到截图内的生产者提前生产了,这个属于正常现象,对程序影响不大,也有办法解决。

    在消费者线程起来了之后,可以看到在消费者代码中如果代码没执行完 freeSpace生产者线程是不会释放的,会阻塞生产者线程。

    达到一生产一消费的状态。

作者踩坑细节,大家注意了,来打起精神来,本文最精彩的部分来了,也是本来想着十点钟发出来最后十一点多才发出来的原因,彻底的打乱了我更新的步伐...

遇到的问题 1

如何实现生产一个多个消费,下图为何执行的丝般顺滑??? 如果你按照我上图的做了,同时看到这里发现执行不出来,请往下看

本文有借鉴部分

上图的丝般顺滑是如何做到的?按照博主做一遍不太管用?本来想着按照这些博客抄一遍就好,但是自己的良心过不去.....

遇到这个问题最大的原因就是因为 release 和 acquire 两个参数的原因,因为创建和销毁的时机不一样所以才会导致你的代码没有图片的丝般顺滑。

遇到的问题 2

如果没有release怎么办,答案是程序假死,一直在等release,没等到release就不走,赖到那了,不给钱起不来

遇到的问题 3

如果睡着了怎么办,那就只能等它到自然醒...

QSemaphore生产者消费者模式,对于线程同步还是很有作用的

觉得写的还可以就点点赞把

完整版项目连接:https://mp.csdn.net/console/upDetailed

有其它问题或者建议请留言

其它线程文章:

QT 初识线程(简单实现):https://blog.csdn.net/qq_37529913/article/details/110127940

QT QMutex使用详解:https://blog.csdn.net/qq_37529913/article/details/110187452

QT 线程之QSemaphore(深入理解):https://blog.csdn.net/qq_37529913/article/details/110187121

QT线程 Emit、Sgnals、Slot详细解释:https://blog.csdn.net/qq_37529913/article/details/110211435

QT 线程之QWaitCondition(深入理解):https://blog.csdn.net/qq_37529913/article/details/110212704

Qt 多线程之线程事件循环(深入理解):https://blog.csdn.net/qq_37529913/article/details/110229382

QT线程之QObjects(深入理解):https://blog.csdn.net/qq_37529913/article/details/110228837

QT线程之可重入与线程安全(深入理解):https://blog.csdn.net/qq_37529913/article/details/110224166

QT之浅拷贝、深拷贝、隐式共享(深度理解必看文章):https://blog.csdn.net/qq_37529913/article/details/110235596

QT 隐式共享机制对STL样式迭代器的影响:https://blog.csdn.net/qq_37529913/article/details/110252454

猜你喜欢

转载自blog.csdn.net/qq_37529913/article/details/110187121