在项目中我采用了QThreadPool使用多线程,但是因为线程操作的是临界资源,所以在我需要保证下一次短时间内的任务更改生效,我必须先停止之前线程未完成的操作步骤,即停止线程内的后台任务。
***********************************分割线------------------------------------------
任务类头文件
#ifndef TASK_H
#define TASK_H
#include <QRunnable>
#include <QObject>
class Task : public QObject,public QRunnable {
//多继承,为了前者为了信号和槽函数连接,后者为了配合QThreadPool
Q_OBJECT
public:
Task();
~Task();
void run() Q_DECL_OVERRIDE;
public slots:
void setCancel();
private:
bool m_isstop;
signals:
void load_over();
};
#endif // TASK_H
任务实现
#include "task.h"
#include <QDebug>
#include <QDateTime>
Task::Task() :m_isstop(false) {
}
Task::~Task() {
qDebug().noquote() << QString("~Task() with ID %1").arg(m_id); // 方便查看对象是否被 delete
}
void Task::run() {
for(int i = 0;i < 10000;i++)
{
if(m_isstop)
{
qDebug()<<"Stop thread Work. thread ID:"<<QThread::currentThreadId();
break;//退出任务
}
sleep(10000000);//耗时操作
}
emit load_over();//发送完成信号
}
void Task::setCancel()
{
m_isstop = true;//收到取消信号后改变bool变量
}
主操作界面头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include <QThreadPool>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QThreadPool *Q_pool;
Task *task;
private slots:
void on_pushButton_clicked();//开始按键
void on_pushButton1_clicked();//停止按键
private:
Ui::MainWindow *ui;
signals:
void stop();
public slots:
void over();
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <fstream>
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
m_workThread.quit();
m_workThread.wait();
}
void MainWindow::over()
{
ui->pushButton->setEnabled(true);
}
void MainWindow::on_pushButton_clicked()//开启线程
{
ui->pushButton->setEnabled(false);//取消按键使能避免多个加入多个线程
Q_pool = new QThreadPool();
Q_pool->setMaxThreadCount(1);
Task *task = new Task(filename);
connect(this,SIGNAL(stop()),task,SLOT(setCancel()));
connect(task,SIGNAL(load_over()),this,SLOT(over()));
Q_pool->globalInstance()->start(task);
}
void MainWindow::on_pushButton1_clicked()//停止线程
{
emit stop();
ui->pushButton->setEnabled(true);
}
void MainWindow::start(int i)
{
qDebug()<<"num:"<<i<<endl;
emit start_work(i);
}
***********************************分割线------------------------------------------
tips:若QRunnable未设置deleteauto属性为false,则交由线程池进行释放
最终实现效果如下:
1.开启线程任务前
2.开启线程任务后台运行时
3.点击stop按键或者线程任务结束后
心得:在项目中因为是在解析文件写入数据到一个数据库,因为写入时间较长,为避免用户操作过快,上一个写入还未完成便开启下个无关文件的数据载入造成数据错乱或者数据库连接过多,所以通过这种槽函数和信号的机制避开极端情况