前言
多线程在实际项目编程中是非常常用的,下面按照以下几点进行介绍:
正文
1. 线程介绍
因为进程的创建、切换需要大量的时间和空间的消耗,因此在上世纪80年代诞生了一种SMP(Symmetrical Multi-Processing)的对称多处理技术,这就是线程。
线程的创建、切换所需的消耗要比进程小很多,这是因为进程需要一块完整的地址空间,而线程只是进程中的最小执行单元,共享进程的地址空间,不需要创建新的资源。
1.1 线程和进程的区别
区别 | 线程 | 进程 |
---|---|---|
根本区别 | 是处理器任务调度和执行的最小单位 | 是操作系统资源调度的最小单位 |
资源开销 | 同进程下的线程共享进程的资源 | 进程之间的资源相互独立 |
包含关系 | 线程是进程的最小执行单元 | 进程包含多个线程 |
1.2 线程调度
Windows操作系统在启动后就会开始检查可调度线程内核对象,选择一个线程的内核对象,将其上下文载入CPU寄存器,然后线程开始运行。
线程的调度机制是由调度算法决定的,通用调度算法有:
-
先进先出算法(FIFO)
按照任务进入队列的顺序,依次调度。 -
最短耗时任务优先算法(SJF)
按照任务的耗时长短进行调度,耗时短的任务优先调度。 -
时间片轮转算法(Round Robin)
给队列中的每个任务一个时间片,第一个任务先执行,时间片结束后将任务放到队列末尾,然后切换到下个任务执行。 -
最大最小公平算法(Max-Min Fairness)
平均分配资源;
有剩余资源的则平均分配给其他任务;
资源不够则等待; -
多级反馈队列算法(Multi-level Feedback Queue)
算法按照优先级从高到低排序,优先级越低分片时长越大;
高优先级任务可以抢占低优先级任务;
任务在一个时间片结束时,若任务结束,则正常退出系统,若任务还没结束,则降低一个等级;
任务如果因为等待I/O响应而主动让出CPU,则保留当前等级(或者是提高一个等级);
同一等级的任务采用时间片轮转算法(Round Robin);
2. QThread介绍
QThread类提供不依赖平台的管理线程的方法。一个QThread类的对象管理一个线程,一般实现方式有两种:
- 继承QThread类,并重定义虚函数run(),在run()函数实现耗时任务
- 继承QObject类,自定义槽函数实现耗时任务,通过moveToThread来改变对象的线程亲和力
2.1 QThread基础
QThread是Qt线程中的抽象类,所有的线程类都是从QThread抽象类中派生出来的。
下面列举主要函数:
类型 | 函数 | 功能 |
---|---|---|
public | void setPriority(Priority priority) | 设置线程的优先级 |
public | void exit(int returenCode = 0) | 退出线程的事件循环 |
public | bool wait(unsigned long time) | 阻塞等待线程结束,直到time毫秒后 |
public slot | void quit() | 退出线程的事件循环 |
public slot | void start(Priority priority) | 内部调用run()开始执行线程,操作系统根据priority参数进行调度 |
public slot | void terminate() | 终止线程的运行,不是立即结束线程,而是等待操作系统结束线程。使用terminate()之后应使用wait() |
signal | void finished() | 在线程结束时发送该信号 |
signal | void started() | 在线程开始执行时,run()被调用之前发送该信号 |
protected | virtual void run() | start()调用run()开始线程任务的执行,在run()中实现线程的处理任务 |
protected | int exec() | 由run()调用,进入线程的事件循环,等待exit()退出 |
QThread线程有8个优先级:
优先级 | 注释 |
---|---|
QThread::IdlePriority | 仅在没有其他线程运行的情况下执行 |
QThread::LowestPriority | 优先级低于LowPriority |
QThread::LowPriority | 优先级低于NormalPriority |
QThread::NormalPriority | 操作系统的默认优先级 |
QThread::HighPriority | 优先级高于NormalPriority |
QThread::HighestPriority | 优先级高于HighPriority |
QThread::TimeCriticalPriority | 尽可能频繁运行 |
QThread::InheritPriority | 使用与创建线程相同的优先级(默认) |
2.2 继承QThread类
按照官网的介绍,主要是以下两点:
- 不在run()中调用exec(),就不会运行事件循环
- QThread派生的实例对象除了run()在新线程中执行外,其他(构造函数、槽函数等)都在创建该对象的线程中执行
下面测试一下:
class WorkerThd : public QThread
{
Q_OBJECT
public:
WorkerThd(QObject* parent = nullptr) : QThread(parent) {
}
void run() override {
qDebug() << "ThreadID of the run(): " << QThread::currentThreadId();
}
Q_SLOT void doOtherWork() {
qDebug() << "ThreadID of the doOtherWork(): " << QThread::currentThreadId();
}
};
class Controller : public QObject
{
Q_OBJECT
public:
Controller(QObject* parent = nullptr) : QObject(parent) {
workThd = new WorkerThd(this);
connect(this, &Controller::sigDoOtherWork, workThd, &WorkerThd::doOtherWork);
connect(workThd, &QThread::finished, workThd, &QObject::deleteLater);
workThd->start();
}
~Controller() {
w