文章目錄
- 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();
}
小結
??學習,加油,共勉。