基于互斥量的线程同步

这个基于上上一次的博客
为什么需要互斥量?
你想你的主线程是用来显示色子的情况的,子线程是处理色子的数据,假如不用信号与槽的机制,如何告诉主线程色子的情况,主线程就有可能非法地打断子线程的工作,得到错误的数据。
如何解决这个问题?
使用互斥量来实现,这个互斥量就如同一把锁,子线程在工作的时候主线程无法打断。
代码如下:
qdicethread.h:

#ifndef QDICETHREAD_H
#define QDICETHREAD_H
#include <QThread>
#include <QMutex>
class QDiceThread:public QThread
{
    Q_OBJECT
private:
    //互斥量
    QMutex mutex;
    //掷色子次数序号
    int m_seq=0;
    //色子点数
    int m_diceValue;
    //暂停
    bool m_Paused=true;
    //停止
    bool m_stop=false;
protected:
    //线程任务
    void run() Q_DECL_OVERRIDE;
public:
    QDiceThread();
    void diceBegin();
    void dicePause();
    void stopThread();
    //返回m_diceValue的值
   // int diceValue();
    //用于主线程读取数据的函数
    bool readValue(int *seq,int *diceValue);
signals:
    //void newValue(int seq,int diceValue);
};

#endif // QDICETHREAD_H

qdicethread.cpp:

#include "qdicethread.h"
#include <QTime>
QDiceThread::QDiceThread()
{

}
//开始掷色子
void QDiceThread::diceBegin()
{
    m_Paused=false;

}
//暂停掷色子
void QDiceThread::dicePause()
{
    m_Paused=true;
}
//停止线程
void QDiceThread::stopThread()
{
    m_stop=true;
}



//int QDiceThread::diceValue()
//{
//    return m_diceValue;
//}
//线程任务
void QDiceThread::run()
{
    m_stop=false;
    m_seq=0;
    //随机数初始化 qsrand是线程安全的
    qsrand(QTime::currentTime().msec());
    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);
    }
    quit();
}
bool QDiceThread::readValue(int *seq, int *diceValue)
{
    if(mutex.tryLock()){
        *seq=m_seq;
        *diceValue=m_diceValue;
        mutex.unlock();
        return true;
    }
    else{
        return false;
    }
}



mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qdicethread.h"
#include <QTimer>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    int mSeq,mDiceValue;
    QDiceThread threadA;
    //定时器
    QTimer mTimer;
protected:
    void closeEvent(QCloseEvent *event);
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void on_btn_qd_clicked();

    void on_btn_start_clicked();

    void on_btn_down_clicked();

    void on_btn_over_clicked();

    void on_btn_clear_clicked();

    //自定义槽函数
    void onthreadA_started();
    void onthreadA_finished();
   // void onthread_newValue(int seq,int diceValue);
    void onTimeOut();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#pragma execution_character_set("utf-8")
#include <QDebug>



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(&threadA,SIGNAL(started()),this,SLOT(onthreadA_started()));
    connect(&threadA,SIGNAL(finished()),this,SLOT(onthreadA_finished()));
//    connect(&threadA,SIGNAL(newValue(int,int)),this,SLOT(onthread_newValue(int,int)));
    connect(&mTimer,SIGNAL(timeout()),this,SLOT(onTimeOut()));
}

void MainWindow::onthreadA_started()
{
    ui->label_state->setText("线程状态:thread started");
}

void MainWindow::onthreadA_finished()
{
    ui->label_state->setText("线程状态:thread over");
}

void MainWindow::onTimeOut()
{
    int tmpSeq=0,tmpValue=0;
    bool valid=threadA.readValue(&tmpSeq,&tmpValue);
    if(valid&&(tmpSeq!=mSeq)){
        mSeq=tmpSeq;
        mDiceValue=tmpValue;
        QString str=QString::asprintf("第 %d 次掷色子,点数为: %d",mSeq,mDiceValue);
        ui->plainTextEdit->appendPlainText(str);

    }

}

//void MainWindow::onthread_newValue(int seq, int diceValue)
//{
//    QString str=QString::asprintf("第 %d 次掷色子,点数为: %d",seq,diceValue);
//    ui->plainTextEdit->appendPlainText(str);
//}

//启动线程
void MainWindow::on_btn_qd_clicked()
{
     mSeq=0;
    threadA.start();

    //启动线程
    ui->btn_qd->setEnabled(false);
    //结束线程
    ui->btn_over->setEnabled(true);
    //开始按钮
    ui->btn_start->setEnabled(true);
    //暂停按钮
    ui->btn_down->setEnabled(false);
}
//结束线程
void MainWindow::on_btn_over_clicked()
{
    threadA.stopThread();
    threadA.wait();
    ui->btn_qd->setEnabled(true);
    ui->btn_over->setEnabled(false);
    ui->btn_start->setEnabled(false);
    ui->btn_down->setEnabled(false);
}
//开始
void MainWindow::on_btn_start_clicked()
{
    threadA.diceBegin();
    mTimer.start(100);
    ui->btn_start->setEnabled(false);
    ui->btn_down->setEnabled(true);


}
//暂停
void MainWindow::on_btn_down_clicked()
{
    threadA.dicePause();
    mTimer.stop();
    ui->btn_start->setEnabled(true);
    ui->btn_down->setEnabled(false);

}

//清空
void MainWindow::on_btn_clear_clicked()
{

    ui->plainTextEdit->clear();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    if(threadA.isRunning()){
        threadA.stopThread();
        threadA.wait();
    }
    event->accept();

}
MainWindow::~MainWindow()
{
    delete ui;
}



仔细分析以上修改的程序,你就会有不一样的收获,可以参考上上一篇博客
Qt创建多线程程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值