文章目录
- Qt编程技巧总结篇(3)-信号-槽-多线程(二)
- 主进程与子线程
- 线程同步
- 实例与应用
- 小结
Qt编程技巧总结篇(3)-信号-槽-多线程(二)
多线程学习,使用QMutex,好了,开整~
主进程与子线程
主进程:经常处于空闲状态,仅处理短小精悍、不怎么占用时间的“小”函数。
子线程:处理主要的计算啊!存储啊!循环等复杂费时的任务。
线程同步
线程同步:子线程中运算量较大的函数在执行的过程中不希望被主线程调用,放置该函数的中断, 因而这类函数需要被保护起来,令其在执行过程中不能被其他线程打断,以保证计算机结果的完整性。
线程同步可以使用:QMutex,QMutexLocker,QReadWriteLock,QReadLocker, QWriteLocker,QWaitCondition,QSemaphore.
这里的例子主要是:QMutex
与QMutexLocker
的应用。
实例与应用
下面的例子是《 QT5.9 c++ 开发指南》中的例子,代码放这里,欢迎参考学习!
子线程.h: qdicethread.h文件,
#ifndef QDICETHREAD_H
#define QDICETHREAD_H#include <QObject>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QTime>class QDiceThread : public QThread
{Q_OBJECT
public:QDiceThread();void diceBegin(); // 投色子void diceEnd(); // 读色子void stopThread(); // 停止线程bool readVal(int *seq,int *diceValue); // 主线程读色子private:QMutex mutex; //互斥量int m_seq = 0;int m_diceVal;bool m_pause = true;bool m_stop=false;protected:void run() Q_DECL_OVERRIDE;
};#endif // QDICETHREAD_H
子线程.h:qdicethread.cpp 文件,
#include "qdicethread.h"QDiceThread::QDiceThread()
{}void QDiceThread::diceBegin()
{m_pause = false;
}void QDiceThread::diceEnd()
{m_pause = true;
}void QDiceThread::stopThread()
{m_stop = true;
}bool QDiceThread::readVal(int *seq, int *diceValue)
{if(mutex.tryLock()) //试图锁定一个互斥量,成功返回true。{*seq = m_seq;*diceValue = m_diceVal;mutex.unlock();return true;}else{return false;}
}void QDiceThread::run()
{m_stop = false;m_seq = 0;qsrand(QTime::currentTime().msec()); // 随机数初始化,qsrand是线程安全的while(!m_stop){/* mutex.lock() 与 mutex.unlock() 配对使用 */
// if(!m_pause)
// {
// mutex.lock(); //锁定互斥量,他将阻塞执行直到其他线程解锁这个互斥量
// m_diceVal = qrand();
// m_diceVal = (m_diceVal%6)+1;
// m_seq++;
// mutex.unlock(); // 解锁互斥量
// }/* 在一些逻辑复杂的代码中,上述方法配对容易出错,可采用QMutexLocker的方法进行简化 */if(!m_pause){QMutexLocker Locker(&mutex);m_diceVal = qrand();m_diceVal = (m_diceVal%6)+1;m_seq++;}msleep(100); // 休眠100ms}
}
主线程.h :dialog.h文件,
#ifndef DIALOG_H
#define DIALOG_H#include <QDebug>
#include <QDialog>
#include <QTimer>
#include "qdicethread.h"QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }class Dialog : public QDialog
{Q_OBJECT// 需要写在前面
private:int mSeq,mDiceValue;QDiceThread threadA;QTimer mTimer;//定时器public:Dialog(QWidget *parent = nullptr);~Dialog();private slots:void onthreadA_started();void onthreadA_finished();void onTimeOut(); //定时器处理槽函数????void on_btnStartThread_clicked();void on_btnDiceBegin_clicked();void on_btnDiceEnd_clicked();void on_btnStopThread_clicked();void on_btnClear_clicked();private:Ui::Dialog *ui;protected:void closeEvent(QCloseEvent *evet);};
#endif // DIALOG_H
主线程.cpp :dialog.cpp文件,
- 连接槽函数与信号函数
#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{ui->setupUi(this);connect(&threadA,SIGNAL(started()),this,SLOT(onthreadA_started()));connect(&threadA,SIGNAL(finished()),this,SLOT(onthreadA_finished()));connect(&mTimer,SIGNAL(timeout()),this,SLOT(onTimeOut()));}Dialog::~Dialog()
{delete ui;
}void Dialog::onthreadA_started()
{ui->LabA->setText("Thread 状态:thread started.");
}void Dialog::onthreadA_finished()
{ui->LabA->setText("Thread 状态:thread finished.");
}void Dialog::onTimeOut()
{int tmpSeq=0,tmpValue=0;bool valid = threadA.readVal(&tmpSeq, &tmpValue);if(valid && (tmpSeq != mSeq)) // 获取的是有效且新的数据{qDebug()<<tmpSeq;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_btnStartThread_clicked()
{mSeq = 0;threadA.start();ui->btnStartThread->setEnabled(false);ui->btnStopThread->setEnabled(true);ui->btnDiceBegin->setEnabled(true);ui->btnDiceEnd->setEnabled(false);
}void Dialog::on_btnDiceBegin_clicked()
{threadA.diceBegin();mTimer.start(100); //定时器100ms读一次数据ui->btnDiceBegin->setEnabled(false);ui->btnDiceEnd->setEnabled(true);
}void Dialog::on_btnDiceEnd_clicked()
{threadA.diceEnd();mTimer.stop(); // 暂停定时器ui->btnDiceBegin->setEnabled(true);ui->btnDiceEnd->setEnabled(false);
}void Dialog::on_btnStopThread_clicked()
{threadA.stopThread();threadA.wait();ui->btnStartThread->setEnabled(true);ui->btnStopThread->setEnabled(false);ui->btnDiceBegin->setEnabled(false);ui->btnDiceEnd->setEnabled(false);
}void Dialog::on_btnClear_clicked()
{ui->plainTextEdit->clear();
}void Dialog::closeEvent(QCloseEvent *evet)
{if(threadA.isRunning()){threadA.stopThread();threadA.wait();}evet->accept();
}
主函数:main.cpp文件,
#include "dialog.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Dialog w;w.show();return a.exec();
}
小结
学习,加油,共勉。