在 qt 中使用了多线程,有些事项是需要额外注意的:
1.默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新;
2.子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理;
3.主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制。
Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一共提供了两种创建子线程的方式,后边会依次介绍其使用方式。先来看一下这个类中提供的一些常用 API 函数:
- // QThread 类常用 API
- // 构造函数
- QThread::QThread(QObject *parent = Q_NULLPTR);
- // 判断线程中的任务是不是处理完毕了
- bool QThread::isFinished() const;
- // 判断子线程是不是在执行任务
- bool QThread::isRunning() const;
-
- // 退出线程的工作函数
- void QThread::exit(int returnCode = 0);
- // 调用线程退出函数之后, 线程不会马上退出因为当前任务有可能还没有完成, 调回用这个函数是
- // 等待任务完成, 然后退出线程, 一般情况下会在 exit() 后边调用这个函数
- bool QThread::wait(unsigned long time = ULONG_MAX);
- // 和调用 exit() 效果是一样的
- // 代用这个函数之后, 再调用 wait() 函数
- [slot] void QThread::quit();
- // 启动子线程
- [slot] void QThread::start(Priority priority = InheritPriority);
- // 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
- [slot] void QThread::terminate();
-
- // 线程中执行的任务完成了, 发出该信号
- // 任务函数中的处理逻辑执行完毕了
- [signal] void QThread::finished();
- // 开始工作之前发出这个信号, 一般不使用
- [signal] void QThread::started();
- // 返回一个指向管理当前执行线程的QThread的指针
- [static] QThread *QThread::currentThread();
- // 返回可以在系统上运行的理想线程数 == 和当前电脑的 CPU 核心数相同
- [static] int QThread::idealThreadCount();
- // 线程休眠函数
- [static] void QThread::msleep(unsigned long msecs); // 单位: 毫秒
- [static] void QThread::sleep(unsigned long secs); // 单位: 秒
- [static] void QThread::usleep(unsigned long usecs); // 单位: 微秒
这个 run() 是一个虚函数,如果想让创建的子线程执行某个任务,需要写一个子类让其继承 QThread,并且在子类中重写父类的 run() 方法,函数体就是对应的任务处理流程。另外,这个函数是一个受保护的成员函数,不能够在类的外部调用,如果想要让线程执行这个函数中的业务流程,需要通过当前线程对象调用槽函数 start() 启动子线程,当子线程被启动,这个 run() 函数也就在线程内部被调用了。
- // 子线程要处理什么任务, 需要写到 run() 中
- [virtual protected] void QThread::run();
- #ifndef MYTHREAD_H
- #define MYTHREAD_H
-
- #include
-
- class MyThread : public QThread
- {
- Q_OBJECT
- public:
- explicit MyThread(QObject *parent = nullptr);
-
- protected:
- void run();
-
- signals:
- // 自定义信号, 传递数据
- void curNumber(int num);
-
- public slots:
- };
-
- #endif // MYTHREAD_H
- #include "mythread.h"
- #include
-
- MyThread::MyThread(QObject *parent) : QThread(parent)
- {
-
- }
-
- void MyThread::run()
- {
- qDebug() << "当前线程对象的地址: " << QThread::currentThread();
-
- int num = 0;
- while(1)
- {
- emit curNumber(num++);
- if(num == 10000000)
- {
- break;
- }
- QThread::usleep(1);
- }
- qDebug() << "run() 执行完毕, 子线程退出...";
- }
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include "mythread.h"
- #include
-
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
-
- qDebug() << "主线程对象地址: " << QThread::currentThread();
- // 创建子线程
- MyThread* t1= new MyThread;
-
- connect(t1, &MyThread::curNumber, this, [=](int num)
- {
- ui->label->setNum(num);
- });
-
- connect(ui->startBtn, &QPushButton::clicked, this, [=]()
- {
- // 启动子线程
- t1->start();
- });
- }
-
- MainWindow::~MainWindow()
- {
- delete ui;
- }
- #ifndef MYTHREAD_H
- #define MYTHREAD_H
-
- #include
- #include
-
- // 生成随机数
- class Generate : public QObject
- {
- Q_OBJECT
- public:
- explicit Generate(QObject *parent = nullptr);
-
-
- void working(int num);
-
- signals:
- void sendArray(QVector<int> num);
-
- };
-
-
- class BubbleSort : public QObject
- {
- Q_OBJECT
- public:
- explicit BubbleSort(QObject *parent = nullptr);
-
- void working(QVector<int> list);
-
- signals:
- void finish(QVector<int> num);
-
- };
-
-
- class QuickSort : public QObject
- {
- Q_OBJECT
- public:
- explicit QuickSort(QObject *parent = nullptr);
-
- void working(QVector<int> list);
-
- private:
- void quickSort(QVector<int> &list, int l, int r);
-
- signals:
- void finish(QVector<int> num);
-
- };
-
- #endif // MYTHREAD_H
- #include "mythread.h"
- #include
- #include
- #include
-
- Generate::Generate(QObject *parent) : QObject(parent)
- {
-
- }
-
- void Generate::working(int num)
- {
- qDebug() << "生成随机数的线程的线程地址: " << QThread::currentThread();
- QVector<int> list;
- QElapsedTimer time;
- time.start();
- for(int i=0; i
- {
- list.push_back(qrand() % 100000);
- }
- int milsec = time.elapsed();
- qDebug() << "生成" << num << "个随机数总共用时:" << milsec << "毫秒";
- emit sendArray(list);
- }
-
- BubbleSort::BubbleSort(QObject *parent) : QObject(parent)
- {
-
- }
-
- void BubbleSort::working(QVector<int> list)
- {
- qDebug() << "冒泡排序的线程的线程地址: " << QThread::currentThread();
- QElapsedTimer time;
- time.start();
- int temp;
- for(int i=0; i
size(); ++i) - {
- for(int j=0; j
size()-i-1; ++j) - {
- if(list[j] > list[j+1])
- {
- temp = list[j];
- list[j] = list[j+1];
- list[j+1] = temp;
- }
- }
- }
- int milsec = time.elapsed();
- qDebug() << "冒泡排序用时" << milsec << "毫秒";
- emit finish(list);
- }
-
- QuickSort::QuickSort(QObject *parent) : QObject(parent)
- {
-
- }
-
- void QuickSort::working(QVector<int> list)
- {
- qDebug() << "快速排序的线程的线程地址: " << QThread::currentThread();
- QElapsedTimer time;
- time.start();
- quickSort(list, 0, list.size()-1);
- int milsec = time.elapsed();
- qDebug() << "排序用时" << milsec << "毫秒";
- emit finish(list);
- }
-
- void QuickSort::quickSort(QVector<int> &s, int l, int r)
- {
- if (l < r)
- {
- int i = l, j = r;
- // 拿出第一个元素, 保存到x中,第一个位置成为一个坑
- int x = s[l];
- while (i < j)
- {
- // 从右向左找小于x的数
- while (i < j && s[j] >= x)
- {
- //左移, 直到遇到小于等于x的数
- j--;
- }
- if (i < j)
- {
- //将右侧找到的小于x的元素放入左侧坑中, 右侧出现一个坑
- //左侧元素索引后移
- s[i++] = s[j];
- }
-
- // 从左向右找大于等于x的数
- while (i < j && s[i] < x)
- {
- //右移, 直到遇到大于x的数
- i++;
- }
- if (i < j)
- {
- //将左侧找到的元素放入右侧坑中, 左侧出现一个坑
- //右侧元素索引向前移动
- s[j--] = s[i];
- }
- }
- //此时 i=j,将保存在x中的数填入坑中
- s[i] = x;
- quickSort(s, l, i - 1); // 递归调用
- quickSort(s, i + 1, r);
- }
- }
-
mainwindow.h:
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
-
- #include
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class MainWindow; }
- QT_END_NAMESPACE
-
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
-
- public:
- MainWindow(QWidget *parent = nullptr);
- ~MainWindow();
-
- signals:
- void starting(int num);
-
- private:
- Ui::MainWindow *ui;
- };
- #endif // MAINWINDOW_H
mainwindow.cpp:
- #include "mainwindow.h"
- #include "ui_mainwindow.h"
- #include "mythread.h"
- #include
-
- MainWindow::MainWindow(QWidget *parent)
- : QMainWindow(parent)
- , ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
-
- // 1. 创建子线程对象
- QThread* t1 = new QThread;
- QThread* t2 = new QThread;
- QThread* t3 = new QThread;
-
- // 2. 创建任务类的对象
- Generate* gen = new Generate;
- BubbleSort* bubble = new BubbleSort;
- QuickSort* quick = new QuickSort;
-
- // 3. 将任务对象移动到某个子线程中
- gen->moveToThread(t1);
- bubble->moveToThread(t2);
- quick->moveToThread(t3);
-
-
- connect(this, &MainWindow::starting, gen, &Generate::working);
- // 2. 启动子线程
- connect(ui->start, &QPushButton::clicked, this, [=]()
- {
- emit starting(10000);
- t1->start();
- });
- connect(gen, &Generate::sendArray, bubble, &BubbleSort::working);
- connect(gen, &Generate::sendArray, quick, &QuickSort::working);
- // 接收子线程发送的数据
- connect(gen, &Generate::sendArray, this, [=](QVector<int> list){
- t2->start();
- t3->start();
- for(int i=0; i
size(); ++i) - {
- ui->randList->addItem(QString::number(list.at(i)));
- }
- });
- connect(bubble, &BubbleSort::finish, this, [=](QVector<int> list){
- for(int i=0; i
size(); ++i) - {
- ui->bubbleList->addItem(QString::number(list.at(i)));
- }
- });
- connect(quick, &QuickSort::finish, this, [=](QVector<int> list){
- for(int i=0; i
size(); ++i) - {
- ui->quickList->addItem(QString::number(list.at(i)));
- }
- });
-
- connect(this, &MainWindow::destroy, this, [=]()
- {
- t1->quit();
- t1->wait();
- t1->deleteLater(); // delete t1;
-
- t2->quit();
- t2->wait();
- t2->deleteLater();
-
- t3->quit();
- t3->wait();
- t3->deleteLater();
-
- gen->deleteLater();
- bubble->deleteLater();
- quick->deleteLater();
- });
-
- }
-
- MainWindow::~MainWindow()
- {
- delete ui;
- }
-
main.cpp:
- #include "mainwindow.h"
-
- #include
-
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- qRegisterMetaType
int>>("QVector" ); - MainWindow w;
- w.show();
- return a.exec();
- }
详情代码请见: