• qt线程介绍


    目录

    介绍

     线程类 QThread

     方式1

    方式2

    案例

    线程资源释放


    介绍

    qt为多线程提供了完美的支持,实现多线程一般是从从QTHread中继承定义自己的线程类,QT也提供了QMutexLocker,QwaitCondition等类实现线程同步,与Linux系统或C++中的线程库类似。这里简单介绍下多线程的创建。

    • 默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新
    • 子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理
    • 主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号槽机制

     线程类 QThread

    常用API:

    [virtual protected] void QThread::run();

    run()是一个虚函数,如果想让创建的子线程执行某个任务,需要写一个子类让其继承QThread,并且在子类中重写父类的run()方法,函数体就是对应的任务处理流程,当前线程对象调用槽函数start()启动子线程,当子线程被启动,这个run()函数也就在线程内部被调用了。

    信号与槽函数:

    // 线程中执行的任务完成了, 发出该信号
    [signal] void QThread::finished();
    // 开始工作之前发出这个信号, 一般不使用
    [signal] void QThread::started();

    [slot] void QThread::quit();


    // 启动子线程
    [slot] void QThread::start(Priority priority = InheritPriority);
    // 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
    [slot] void QThread::terminate();

     方式1

    创建一个线程类的子类,让其继承QT中的线程类 QThread,重写父类的 run() 方法,启动子线程, 调用 start() 方法。

    举例:

    1. #ifndef MYTHREAD_H
    2. #define MYTHREAD_H
    3. #include
    4. #include
    5. class MyThread : public QThread
    6. {
    7. Q_OBJECT
    8. public:
    9. explicit MyThread(QObject *parent = nullptr);
    10. protected:
    11. void run();
    12. signals:
    13. void curNumber(int num);
    14. };
    15. #endif // MYTHREAD_H
    1. #include "mythread.h"
    2. #include
    3. MyThread::MyThread(QObject *parent)
    4. {
    5. }
    6. void MyThread::run()
    7. {
    8. qDebug() << "当前线程对象的地址: " << QThread::currentThread();
    9. int num = 0;
    10. while(1)
    11. {
    12. emit curNumber(num++);//子线程每秒发出一次信号
    13. if(num == 10000000)
    14. {
    15. break;
    16. }
    17. QThread::usleep(1);
    18. }
    19. qDebug() << "run() 执行完毕, 子线程退出...";
    20. }
    1. MainWindow::MainWindow(QWidget *parent)
    2. : QMainWindow(parent)
    3. , ui(new Ui::MainWindow)
    4. {
    5. ui->setupUi(this);
    6. qDebug() << "主线程对象地址: " << QThread::currentThread();
    7. MyThread* m=new MyThread;
    8. connect(m, &MyThread::curNumber, this, [=](int num)//子线程每秒发出一次信号
    9. {
    10. ui->label->setNum(num);
    11. });
    12. connect(ui->pushButton, &QPushButton::clicked, this, [=]()
    13. {
    14. // 启动子线程
    15. m ->start();
    16. });
    17. }
    18. MainWindow::~MainWindow()
    19. {
    20. delete ui;
    21. }

    方式2

    1. 创建一个新的类A,让这个类从QObject派生,这个类中添加一个公共的成员函数来处理对应的任务
    2. 在主线程中创建一个QThread对象
    3. 在主线程中创建工作的类对象A(不能指定父对象)
    4. 将对象A移动到创建的子线程对象中, 需要调用QObject类提供的moveToThread()方法
    5. 启动子线程,调用 start(), 这时候线程启动了, 但是移动到线程中的对象并没有工作
    6. 调用MyWork类对象的工作函数,让这个函数开始执行。

    例如:

    1. #ifndef WORK_H
    2. #define WORK_H
    3. #include
    4. class Work : public QObject
    5. {
    6. Q_OBJECT
    7. public:
    8. explicit Work(QObject *parent = nullptr);
    9. void Working();
    10. signals:
    11. void curNumber(int num);
    12. };
    13. #endif // WORK_H
    1. #include "work.h"
    2. #include
    3. #include
    4. Work::Work(QObject *parent)
    5. : QObject{parent}
    6. {
    7. }
    8. void Work::Working()
    9. {
    10. qDebug() << "当前线程对象的地址: " << QThread::currentThread();
    11. int num = 0;
    12. while(1)
    13. {
    14. emit curNumber(num++);//子线程每秒发出一次信号
    15. if(num == 10000000)
    16. {
    17. break;
    18. }
    19. QThread::usleep(1);
    20. }
    21. qDebug() << "run() 执行完毕, 子线程退出...";
    22. }
    1. MainWindow::MainWindow(QWidget *parent)
    2. : QMainWindow(parent)
    3. , ui(new Ui::MainWindow)
    4. {
    5. ui->setupUi(this);
    6. qDebug() << "主线程对象地址: " << QThread::currentThread();
    7. QThread* sub = new QThread;//创建线程对象
    8. Work* w=new Work; //创建工作对象,该对象包含业务处理方法,不要指定给创建的对象指定父对象
    9. w->moveToThread(sub); //将工作对象移动到子线程中
    10. sub->start();
    11. connect(ui->startBtn, &QPushButton::clicked, w,&Work::Working);
    12. // 显示数据
    13. connect(w, &Work::curNumber, this, [=](int num)
    14. {
    15. ui->label->setNum(num);
    16. });
    17. }

    案例

    在一个子线程程中随机生成1000个数,将这些数据交给另一个子线程去排序,后面将排序的结果返回给主线程,主线程再将数据输出到窗口中。

    这里采用方案1进行演示:

    生成随机数线程:

    1. class Genera : public QThread //该类来生成随机数
    2. {
    3. Q_OBJECT
    4. public:
    5. explicit Genera(QObject *parent = nullptr);
    6. void getnum(int k);
    7. protected:
    8. void run();//重写run方法,生成随机数
    9. private:
    10. int num_; //获取主线程传来的数据,这里为生成随机数的个数
    11. signals:
    12. void sendnum(QVector<int> v);//当随机数生成完后,发射该信号,将数据传给主线程和排序线程
    13. };
    14. Genera::Genera(QObject *parent)
    15. : QThread{parent}
    16. {
    17. }
    18. void Genera::getnum(int k)
    19. {
    20. num_=k;
    21. }
    22. void Genera::run()
    23. {
    24. qDebug()<<"当前线程是"<<" "<currentThread();
    25. QVector<int> v;
    26. QElapsedTimer q;
    27. q.start();
    28. for(int i=0;i
    29. {
    30. v.push_back(qrand()%10000);
    31. }
    32. int m=q.elapsed();
    33. qDebug()<<"生成随机的时间是"<<" "<
    34. emit sendnum(v);
    35. }

    排序线程:

    1. class BubbleSort : public QThread //该类来生成随机数
    2. {
    3. Q_OBJECT
    4. public:
    5. explicit BubbleSort(QObject *parent = nullptr);
    6. void getnum(QVector<int>);//获取生成随机数线程传来的数据
    7. protected:
    8. void run();//进行排序
    9. private:
    10. QVector<int> v;
    11. signals:
    12. void Finish(QVector<int> v);//排序完成后发射该信号,将排序结果给主线程
    13. };
    14. BubbleSort::BubbleSort(QObject *parent)
    15. : QThread{parent}
    16. {
    17. }
    18. void BubbleSort::getnum(QVector<int> list)
    19. {
    20. v=list;
    21. }
    22. void BubbleSort::run()
    23. {
    24. qDebug()<<"当前线程是"<<" "<currentThread();
    25. QElapsedTimer q;
    26. q.start();
    27. for(int i=0;isize();i++)
    28. {
    29. for(int j=0;jsize()-i-1;j++)
    30. {
    31. if(v[j]>v[j+1])
    32. {
    33. int tmp=v[j+1];
    34. v[j+1]=v[j];
    35. v[j]=tmp;
    36. }
    37. }
    38. }
    39. int m=q.elapsed();
    40. qDebug()<<"排序的时间是"<<" "<
    41. emit Finish(v);
    42. }

    主线程:

    1. class MainWindow : public QMainWindow
    2. {
    3. Q_OBJECT
    4. public:
    5. MainWindow(QWidget *parent = nullptr);
    6. ~MainWindow();
    7. signals:
    8. void starting(int num);//生成随机数的个数
    9. private:
    10. Ui::MainWindow *ui;
    11. };
    12. #endif // MAINWINDOW_H
    13. MainWindow::MainWindow(QWidget *parent)
    14. : QMainWindow(parent)
    15. , ui(new Ui::MainWindow)
    16. {
    17. ui->setupUi(this);
    18. //创建子线程
    19. Genera * g=new Genera;//生成随机数
    20. BubbleSort* b=new BubbleSort;//排序
    21. connect(this,&MainWindow::starting,g,&Genera::getnum);
    22. //启动子线程
    23. connect(ui->pushButton,&QPushButton::clicked,this,[=](){
    24. emit starting(1000);//发射该信号,将生成随机数的个数传给子线程
    25. g->start();
    26. });
    27. connect(g,&Genera::sendnum,b,&BubbleSort::getnum);//排序线程接受生成随机数线程传来的数据
    28. //接受子线程传来的排序数
    29. connect(g,&Genera::sendnum,this,[=](QVector<int> v){
    30. //说明随机生成数已生成好
    31. b->start();
    32. for(int i=0;isize();i++)
    33. {
    34. ui->listWidget->addItem(QString::number(v.at(i)));
    35. }
    36. });
    37. connect(b,&BubbleSort::Finish,this,[=](QVector<int> v){
    38. for(int i=0;isize();i++)
    39. {
    40. ui->listWidget_2->addItem(QString::number(v.at(i)));
    41. }
    42. });
    43. }
    44. MainWindow::~MainWindow()
    45. {
    46. delete ui;
    47. }

     结果:

    线程资源释放

    1.创建线程时,给它指明父对象,让其添加到对象树列表中。

    2.手动释放,调用quit,wait,delete:例如,在上面的代码中,new出来的时局部变量:

    1. connect(this,&MainWindow::destroyed,this,[=](){
    2. g->quit();
    3. g->wait();
    4. g->deleteLater();//类似与c++中delete
    5. });

  • 相关阅读:
    脚手架搭建项目package.json配置中依赖的版本问题
    PyTorch混合精度原理及如何开启该方法
    离散数学复习:特殊关系
    实战演练 | 使用纯 SQL 将表复制到新表
    Kubernetes 创建pod的yaml文件-简单版-nginx
    网络编程——socket定义和地址格式
    大二学生JavaScript实训大作业——动漫秦时明月7页 期末网页制作 HTML+CSS+JavaScript 网页设计实例 企业网站制作
    【计算机组成原理】第一章单元测试
    BIGEMAP APP行车(走路)轨迹记录
    windows系统如何查看Linux文件系统中的图片缩略图
  • 原文地址:https://blog.csdn.net/m0_64397669/article/details/133094645