> 文档中心 > QSemaphore的使用+QSemaphore实现循环输出ABC(含源码+注释)

QSemaphore的使用+QSemaphore实现循环输出ABC(含源码+注释)


一、QSemaphore使用示例图

1.1 QSemaphore基本使用示例图

下图为信号量的基本使用示例图,每点击一次按钮则创建一个资源,源码在本文第三节(源码含详细注释)。
在这里插入图片描述

2.2 QSemaphore循环输出ABC示例图

下图为信号量的基本使用示例图,点击启动线程则开始循环输出ABC,源码在本文第四节
在这里插入图片描述

二、信号量、QSemaphore(个人理解)

了解生产者消费者模型(一种设计模式)的会发现信号量和该设计模型有一定类似。顾名思义生产者消费者模型是生产者生产资源,消费者消费资源;而信号量就像如此,存在生产资源和消费资源的情况,生产资源使用release函数,消费资源使用acquire函数(并且可以指定生产和消费的资源个数)

三、QSemaphore的基本使用(源码)

3.1 CThread定义类

CThread.h

#ifndef CTHREAD_H#define CTHREAD_H#include #include #include class CThread : public QThread{    Q_OBJECTpublic:    explicit CThread(QObject *parent = nullptr);    ~CThread();    void run();    QSemaphore *sem() const;private:    QSemaphore * m_sem; //定义一个信号量指针};#endif // CTHREAD_H

CThread.cpp

#include "CThread.h"#include CThread::CThread(QObject *parent)    : QThread(parent){    m_sem = new QSemaphore; //new出信号量,在创建信号量时可指定一个int值为初始已存在的资源数}CThread::~CThread(){    delete m_sem;}void CThread::run(){    int i = 0;    while(i++ != 3)    { m_sem->acquire();   //获取一个资源,当资源不够时将阻塞,直到资源足够 //输出线程id并显示i值 qDebug() << "线程" << QThread::currentThreadId() << QString("获取了第%1个资源").arg(i);    }    qDebug() << "线程" << QThread::currentThreadId() << "循环结束";}QSemaphore *CThread::sem() const{    return m_sem;}

3.2 CMainWindow调用类

CMainWindow.h

#ifndef CMAINWINDOW_H#define CMAINWINDOW_H#include #include "CThread.h"namespace Ui {class CMainWindow;}class CMainWindow : public QMainWindow{    Q_OBJECTpublic:    explicit CMainWindow(QWidget *parent = 0);    ~CMainWindow();private slots:    void on_startBtn_clicked();//创建资源的槽函数private:    Ui::CMainWindow *ui;    CThread  *m_cThread;//线程指针};#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"#include "ui_CMainWindow.h"CMainWindow::CMainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::CMainWindow){    ui->setupUi(this);    //new出CThread对象    m_cThread = new CThread;    m_cThread->start(); //启动线程}CMainWindow::~CMainWindow(){    m_cThread->exit();    m_cThread->wait(1);    delete m_cThread;    delete ui;}void CMainWindow::on_startBtn_clicked(){    //获取信号量变量,并创建一个资源    m_cThread->sem()->release(1);}

四、QSemaphore实现循环输出ABC

4.1 CThread定义类

CThread.h

#ifndef CTHREAD_H#define CTHREAD_H#include #include #include class CThread : public QThread{    Q_OBJECTpublic:    explicit CThread(int n, QObject *parent = nullptr);    ~CThread();    void run();    QSemaphore *currentSem() const;    void setNextSem(QSemaphore *nextSem);    void setFlag(char flag);private:    QSemaphore *m_currentSem;   //定义当前线程的信号量指针    QSemaphore *m_nextSem;      //定义下次运行线程的信号量指针    char m_flag;  //定义char变量存储当前线程的字符};#endif // CTHREAD_H

CThread.cpp

#include "CThread.h"#include CThread::CThread(int n, QObject *parent)    : QThread(parent){    m_currentSem = new QSemaphore(n); //new出信号量,并指定默认资源数}CThread::~CThread(){    delete m_currentSem;}void CThread::run(){    int i = 0;    //循环输出当前字符七次    while(i++ != 7)    { m_currentSem->acquire();   //获取资源 //输出线程id并显示i值 qDebug() << m_flag << QThread::currentThreadId(); QThread::usleep(300000);     //使线程睡眠一段时间(单位:微秒),作用为减缓输出速度 m_nextSem->release(1);  //为下次运行的线程创建资源    }    qDebug() << "线程" << QThread::currentThreadId() << "循环结束";}QSemaphore *CThread::currentSem() const{    return m_currentSem;}void CThread::setNextSem(QSemaphore *nextSem){    m_nextSem = nextSem;}void CThread::setFlag(char flag){    m_flag = flag;}

4.2 CMainWindow调用类

CMainWindow.h

#ifndef CMAINWINDOW_H#define CMAINWINDOW_H#include #include "CThread.h"namespace Ui {class CMainWindow;}class CMainWindow : public QMainWindow{    Q_OBJECTpublic:    explicit CMainWindow(QWidget *parent = 0);    ~CMainWindow();private slots:    void on_startBtn_clicked();  //按钮槽函数(环形唤醒)private:    Ui::CMainWindow *   ui;    QList<CThread *>    m_threadList;   //线程指针容器};#endif // CMAINWINDOW_H

CMainWindow.cpp

#include "CMainWindow.h"#include "ui_CMainWindow.h"CMainWindow::CMainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::CMainWindow){    ui->setupUi(this);    //使用循环为线程链表添加三个线程并运行    for(int index = 0; index != 3; ++index)    { //0 == index? 1: 0,此处为三目运算符,判断条件为0 == index,为true则返回?后面的值,反之返回:后面的值 m_threadList.append(new CThread(0 == index? 1: 0)); m_threadList[index]->setFlag(65 + index);   //设置标识符    }    //将获各个线程的m_currentSem设置到对应的存储位置中    //!这里可以如此理解 (0->1:代表0中创建1的资源)    //! 0->1,1->2,2->0    //! 如此看来则形成了环状的资源创建关系    m_threadList[0]->setNextSem(m_threadList[1]->currentSem());    m_threadList[1]->setNextSem(m_threadList[2]->currentSem());    m_threadList[2]->setNextSem(m_threadList[0]->currentSem());}CMainWindow::~CMainWindow(){    foreach (CThread *thread, m_threadList)    { thread->quit(); thread->wait(1); delete thread;    }    delete ui;}void CMainWindow::on_startBtn_clicked(){    //启动三个线程    m_threadList[0]->start();    m_threadList[1]->start();    m_threadList[2]->start();}

总结

信号量相对互斥锁来说会简单一点,个人感觉信号量和生产者消费者模型非常类似,理解起来也相对简单。因为我信号量使用较少,目前就总结这点叭

相关文档

启动QThread线程的两种方法(含源码+注释)
Qt互斥锁(QMutex)、条件变量(QWaitCondition)讲解+QMutex实现多线程循环输出ABC(含源码+注释)
Qt互斥锁(QMutex)的使用、QMutexLocker的使用(含源码+注释)
QRunnable线程、QThreadPool(线程池)的使用(含源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

解梦吧