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