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();
}
小结
学习,加油,共勉。
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Qt编程技巧总结篇(3)-信号-槽-多线程(二)
发表评论 取消回复