Qt —— 多线程QThread
使用Qt的多线程,十分简单,**QThreadrun**,就可以了run()start()run()QThreadtruefalsewait()QThreadrun()truetrueULONG_MAXrun()falsefinished()
·
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; }
效果:

更多推荐



所有评论(0)