QThread 线程

使用Qt的多线程,十分简单,只需要创建一个**QThread的子类,重写其run**函数,就可以了

相关方法:

方法 说明
run() 线程的入口函数…
start() 通过调用 run() 开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,这个函数什么也不做。
currentThread() 返回一个指向管理当前执行线程的 QThread 的指针。
isRunning() 如果线程正在运行则返回true;否则返回false
sleep() / msleep() / usleep() 使线程休眠,单位为秒 / 毫秒 / 微秒
wait() 阻塞线程,直到满足以下任何一个条件:
与此 QThread 对象关联的线程已经完成执行 (即当它从run()返回时)。如果线程已经完成,这个函数将返回 true。如果线程尚未启动,它也返回 true
已经过了几毫秒。如果时间是 ULONG_MAX(默认值),那么等待永远不会超时 (线程必须从run()返回)。如果等待超时,此函数将返回 false
这提供了与 POSIX pthread_join() 函数类似的功能。
terminate() 终止线程的执行。线程可以立即终止,也可以不立即终止,这取决于操作系统的调度策略。在terminate() 之后使用 QThread::wait() 来确保。
finished() 当线程结束时会发出该信号,可以通过该信号来实现线程的清理工作。

例如,我们可以使用线程来实现一个倒计时程序:

#ifndef THREAD_H
#define THREAD_H

#include <QThread>

class Thread : public QThread {
    Q_OBJECT
   public:
    Thread(QObject *parent = nullptr);

    void run();
   signals:
    void notify();
};

#endif  // THREAD_H

// thread.cpp
#include "thread.h"

Thread::Thread(QObject *parent) : QThread(parent) {}

void Thread::run() {
    // 通过线程,发出信号,从而通知主线程更新计时器
    for (int i = 0; i < 10; ++i) {
        sleep(1);  // 每1s发送一次信号
        emit notify();
    }
}

// widget.cpp
#include "widget.h"

#include "./ui_widget.h"
#include "thread.h"

Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);

    ui->lcdNumber->display(10);

    Thread* th = new Thread(this);

    connect(th, &Thread::notify, this, [this]() {
        int val = ui->lcdNumber->value();
        if (val > 0) {
            ui->lcdNumber->display(--val);
        }
    });

    th->start();	// 启动线程
}

Widget::~Widget() { delete ui; }

Qt 多线程的适用场景

尽管,我们可以使用多线程的方式,使得程序的运行效率大大提高

但是,如果我们占用了用户端计算机的大量资源,导致用户的系统卡顿,这就会使得用户的体验会大大下降

所以一般来说,客户端程序很少会使用多线程把CPU计算资源吃完

相比之下,客户端的多线程,主要用于执行一些耗时的等待IO操作,避免主线程卡死

例如,客户端进程会和服务器进行网络通信,要上传/下载一个很大的文件,耗时很久。对于这种IO密集型操作,如果放到主线程中,就会导致客户端程序卡死,用户的操作无法响应。因此最好的做法是创建一个单独的线程,用于执行这种密集型IO操作,使主线程仍能响应客户


Qt 互斥锁(QMutex)与条件变量(QWaitCondition)

例如,利用互斥锁和条件变量,创建两个线程,按顺序,一个打印[0,100]的奇数,一个打印[0,100]的偶数

#ifndef THREAD_H
#define THREAD_H

#include <QThread>

class ThreadOld : public QThread {
    Q_OBJECT
   public:
    ThreadOld(QObject* parent = nullptr);

    void run();

   signals:
    void notify(int val);
};

class ThreadEvent : public QThread {
    Q_OBJECT
   public:
    ThreadEvent(QObject* parent = nullptr);

    void run();

   signals:
    void notify(int val);
};

#endif  // THREAD_H

// thread.cpp
#include "thread.h"

#include <QMutex>
#include <QWaitCondition>

QMutex g_mutex;
QWaitCondition g_cond;
int g_num = 0;
bool flag = true;  // false 打印奇数; true 打印偶数

ThreadOld::ThreadOld(QObject* parent) : QThread(parent) {}

void ThreadOld::run() {
    while (true) {
        msleep(500);

        g_mutex.lock();
        while (flag == true) {
            g_cond.wait(&g_mutex);
        }

        emit notify(g_num);
        ++g_num;
        if (g_num > 100) {
            break;
        }

        flag = true;
        g_cond.notify_one();

        g_mutex.unlock();
    }
}

ThreadEvent::ThreadEvent(QObject* parent) : QThread(parent) {}

void ThreadEvent::run() {
    while (true) {
        msleep(500);

        g_mutex.lock();
        while (flag == false) {
            g_cond.wait(&g_mutex);
        }

        emit notify(g_num);
        ++g_num;
        if (g_num > 100) {
            break;
        }

        flag = false;
        g_cond.notify_one();

        g_mutex.unlock();
    }
}

// widget.cpp
#include "widget.h"

#include "./ui_widget.h"
#include "thread.h"

Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);

    ThreadOld* th_old = new ThreadOld(this);
    ThreadEvent* th_event = new ThreadEvent(this);

    connect(th_old, &ThreadOld::notify, this,
            [this](int val) { this->ui->lcdNumberOld->display(val); });

    connect(th_event, &ThreadEvent::notify, this,
            [this](int val) { this->ui->lcdNumberEvent->display(val); });

    th_old->start();
    th_event->start();
}

Widget::~Widget() { delete ui; }

效果:

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐