《QT5.9 c++ 开发指南》第13章 QThread 中利用QMutex互斥量

本程序是基于上一章程序来进行,修改,本章就不介绍,传送门:

线程例子

本章知识点:

• lock() : 锁定互斥量 ,如果另外一个线程锁定 了这个互斥量 , 它将阻塞执行直到其他线程f样锁这个互斥量。
• unlock() : 解锁一个互斥量 , 需要与 lock()配对使用 。
• tryLock() : 试图锁定一个互斥量 , 如果成功锁定就返回 true : 如果其他线程已经锁定了这个互斥量,就返回 false , 但不阻塞程序执行。

本文在线程中加入互斥量:

private:
    QMutex  mutex; //加入互斥量
    int     m_seq=0;//掷骰子次数序号
    int     m_diceValue;//骰子点数
    bool    m_Paused = true; //掷一次骰子
    bool    m_stop=false; //停止线程
protected:
    void run() Q_DECL_OVERRIDE;   //线程任务,重载run函数
public:
    QDiceThread();
    void diceBegin();  //掷一次骰子
    void dicePause(); //暂停
    void stopThread();  //结束线程
    bool readValue(int *seq,int *diceValue); //用于主线程读取数据的函数

添加readValue(int *seq,int *diceValue); //用于主线程读取数据的函数:

bool QDiceThread::readValue(int *seq, int *diceValue)
{
     if(mutex.tryLock())
     {
         *seq = m_seq;
         *diceValue = m_diceValue;
         mutex.unlock();
         return true;

     }
     else {
         return false;
     }
}

在run函数中修改成:

void QDiceThread::run()
{
    //线程任务
    m_stop = false; //启动线程 m_stop=false
    m_seq = 0; //掷骰子次数
    qsrand(uint(QTime::currentTime().msec())); //随机数初始化,qsrand是线程安全的
    while (!m_stop) {
        if(!m_Paused)
        {
            mutex.lock();
            m_diceValue = qrand(); //获取随机数
            m_diceValue = (m_diceValue % 6) +1;
            m_seq++;
            mutex.unlock();
//            emit newValue(m_seq,m_diceValue); //发送信号
        }
        msleep(500); //线程休眠500ms
    }

    //  在  m_stop==true时结束线程任务
    quit(); //相当于  exit(0),退出线程的事件循环
}

       在 run()函数中 ,对重新计算假子点数和掷假子次数 的 3 行代码用互斥量 mutex 的 lock()和 unlock()进行了保护,这部分代码的执行就不会被其他线程中断。注意 , lock()与 unlock()必须配对使用 。
       在 readValue()函数中,用互斥量 mutex 的 tryLock()和 unlock()进行了保护。如果 tryLock()成功锁定互斥量 , 读取数值的两行代码执行时不会被中断,执行完后解锁:如果町Lock()锁定失败,函数就立即返回 ,而不会等待 。

 

在页面部分采用定时器的方式来获取数据:

private:
    int mSeq,mDiceValue;
    QDiceThread  threadA;
    QTimer mTimer;

在槽函数中自定义

private slots:
     void onTimeOut();  //定期器处理槽函数

在构造函数中连接槽函数:

    connect(&mTimer,SIGNAL(timeout()),this,SLOT(onTimeOut()));

  有关函数:

void Dialog::onTimeOut()
{
    //定时器处理槽函数
     int tmpSeq=0,tmpValue=0;
     bool vaild = threadA.readValue(&tmpSeq,&tmpValue); //读取数值
     if (vaild && (tmpSeq!=mSeq)) //有效,并且是新数据
     {
         mSeq=tmpSeq;
         mDiceValue=tmpValue;
         QString  str=QString::asprintf("第 %d 次掷骰子,点数为:%d",mSeq,mDiceValue);
         ui->plainTextEdit->appendPlainText(str);
         QPixmap pic;
         QString filename=QString::asprintf(":/dice/images/d%d.jpg",mDiceValue);
         pic.load(filename);
         ui->LabPic->setPixmap(pic);
     }
}

对应的开始按钮,与结束按钮:

void Dialog::on_btnDiceBegin_clicked()
{
    //开始 掷骰子按钮
    threadA.diceBegin();
    mTimer.start(100);
    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(true);
}

void Dialog::on_btnDiceEnd_clicked()
{
    //暂停 掷骰子按钮
    threadA.dicePause();
    mTimer.stop();
    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}

这里设置了mTimer.start(100);  100ms的方式来获取数据,低于线程qsleep的时间就可以。

简单的讲解了互斥锁的概念,简单好理解。需要源码的同学可以联系我。

发布了40 篇原创文章 · 获赞 13 · 访问量 5892

猜你喜欢

转载自blog.csdn.net/weixin_42126427/article/details/104497321