• QT多线程 第一节


    在qt中使用了多线程,有些事项是需要额外注意的:

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

    1. 线程类QThread 

    Qt中提供一个线程类,通过这个类就可以创建子线程了,Qt中一共提供了两种创建子线程的方式。这个类的常用API函数:

     public函数
    QThread(QObject *parent = nullptr)构造函数
    virtual ~QThread()析构函数
    QAbstractEventDispatcher * eventDispatcher() const
    bool isFinished() const判断线程中的任务是不是处理完毕了
    bool isInterruptionRequested() const
    bool isRunning() const判断子线程是不是在执行任务
    int loopLevel() const
    QThread::Priority priority() const得到当前线程的优先级
    void requestInterruption()
    void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
    void setPriority(QThread::Priority priority)设置线程优先级
    void setStackSize(uint stackSize)
    uint stackSize() const
    bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever))
    bool wait(unsigned long time)等待任务完成,然后退出线程,一般情况会在exit()后边调用这个函数
    槽函数
    void exit(int returnCode = 0)退出线程,停止底层的事件循环
    void quit()和调用exit()效果是一样的,使用这个函数后,再调用wait()函数
    void start(QThread::Priority priority = InheritPriority)启动子线程
    void terminate()线程退出,可能是会马上终止线程,一般情况下不使用这个函数
    信号函数
    void finished()线程中执行的任务完成了发出该信号,,任务函数中的处理逻辑执行完毕
    void started()开始工作之前发出这个信号,一般不使用
    静态公共成员
    QThread * create(Function &&f, Args &&... args)
    QThread * currentThread()返回一个指向管理当前执行线程的QThread的指针
    Qt::HANDLE currentThreadId()
    int idealThreadCount()返回可以在系统上运行的理想线程数 == 当前电脑的CPU核心数相同
    void msleep(unsigned long msecs)线程休眠函数 毫秒
    void sleep(unsigned long secs)线程休眠函数 秒
    void usleep(unsigned long usecs)线程休眠函数 微秒
    void yieldCurrentThread()
    受保护的函数
    int exec()
    virtual void run()子线程要处理什么任务,需要写到run()中

    2. 使用方式 1

    2.1 操作步骤

    QT中提供的多线程的第一种使用方式的特点是:简单。操作步骤如下:1. 需要创建一个线程的子类,让其继承QT中的线程类QThread,比如:

    1.  创建一个类对象

    1. class MyThread : public QThread
    2. {
    3. ...
    4. }

    2. 重写父类run()方法,在该函数内部编写子线程要处理的具体的业务流程

    1. class MyThread : public QThread
    2. {
    3. ... ...
    4. protected:
    5. void run()
    6. {
    7. ... ...
    8. }
    9. }

    3. 在主线程中创建子线程对象,new 一个就可以了

    MyThread* subThread = new MyThread;

    4. 启动子线程,调用start()方法

    subThread->start();

    不能在类的外部调用run()方法启动子线程,在外部调用start()相当于让run()开始运行,当子线程创建出来后,父子线程之间的通信可以通过信号槽的方式,注意事项:

    • 在Qt中在子线程中不要操作程序中的窗口类型的对象,不允许,如果操作的了程序就挂了
    • 只有主线程才能操作程序中的窗口对象,默认的线程就是主线程,自己创建的就是子线程

    3. 使用方式 2

    3.1 操作步骤

    Qt提供的第二种线程的创建方式弥补了第一种的缺点,用起来更加灵活,但是这种方式写起来会相对复杂一些,其具体操作步骤如下:

    1.创建一个新的类,让这个类从QObject派生

    1. class MyWork : public QObject
    2. {
    3. ... ...
    4. }

    2. 这个类中添加一个公共的成员函数,函数体就是我们要子线程中执行的业务逻辑

    1. class MyWork : public QObject
    2. {
    3. public:
    4. ... ...
    5. //函数名自己指定,叫什么都可以,参数可以根据实际需求添加
    6. void working();
    7. }

    3. 在主线程中创建一个QThread对象,这就是子线程的对象

    QThread* sub = new QThread;
    

    4. 在主线程中创建工作的类对象(千万不要指定给创建的对象指定父对象)

    MyWork* work = new MyWork;
    

    5. 将MyWork 对象移动到创建的子线程对象中,需要调用QObject类提供的moveToThread()方法

    1. //移动到子线程中工作
    2. work->moveToThread(sub);

    6. 启动子线程,调用start(),这时候线程就启动了,但是移动到线程中的对象并没有工作

    7. 调用MyWork类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的

  • 相关阅读:
    matlab图像的运算有点运算、代数运算、逻辑运算和几何运算
    MybatisPlus搭建项目
    使用rpm包制作本地镜像仓库和使用httpd发布镜像服务实现内网使用yum命令
    人体分割模型ACE2P与M2FP,解析人脸人体各部件属性,语义化分析
    一文了解linux都有哪些常用命令
    安装mosek,license安装位置查找
    数据结构:线性表(栈的实现)
    【解决】VSCode编写C++自定义头文件undefined reference异常问题
    Rust 错误处理
    【MYSQL】表的增删查改
  • 原文地址:https://blog.csdn.net/m0_38036750/article/details/126239808