Qt 三种使用线程方式详解

线程生命周期

在正常情况下线程的生命周期,首先是创建一个线程对象,设置一些线程参数,例如,名字和优先级之类的,这是第一步。然后调用start()方法,这时线程并不会真正开始运行了,此时,只是准备就绪阶段,表示线程可以运行了,但是还没有开始运行。没有开始是因为在等待抢占到CPU的执行权限,一旦获得了执行权限就会开始执行执行run()方法的内容,直到run()方法退出了或者调用了中断后线程才会停止,如下图所示:

线程生命周期

上图中描述的是单个线程,随着线程的增加线程的生命周期会有很多变化,如下图所示:
线程生命周期_2

运行状态中如果使用了sleep()或者wait()等让线程暂停的函数,就会进入阻塞状态,这个状态什么都不做,线程会停在这里。当sleep()的时间到了或者收到了相应的notify()通知时,线程会再次进入就绪状态,等待获取CPU的执行权限。正在执行的线程其执行权限被其他线程抢占了则再次返回就绪状态,多个线程正常运行情况下会一直在就绪和运行两个状态来回切换。

创建与使用

QThread

创建

在Qt中继承QThread是常规的实现线程的方式,只需要继承后重写其中的run()函数(大多数线程操作都是重写run()函数)并实现自己的线程工作即可。

// ThreadObject.h
#pragma once
#include <QThread>

class ThreadObject
    : public QThread
{
    Q_OBJECT
public:
    ThreadObject();
    ~ThreadObject();
public slots:
    void StopThread();
protected:
    virtual void run() override;
private:
    bool        is_stop_;
    int         count_;
};
// ThreadObject.cpp
#include "ThreadObject.h"
#include <QDebug>
#include<windows.h> 

ThreadObject::ThreadObject()
    : is_stop_(false)
    , count_(0) {  }
    
ThreadObject::~ThreadObject() = defalut;

void ThreadObject::StopThread()
{
    is_stop_ = true;
}

void ThreadObject::run()
{
    while (!is_stop_) {
        qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Count: " << ++count_;
        sleep(3);
    }
    qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Exit";
}

运行效果
QThread线程启动

在上面的代码中ThreadObject继承了QThread并重写了run()方法,每次点击创建按钮都会创建一个新的线程并在run()函数中每隔3秒打印一次,而且在个线程中的计数变量互相之间并不影响,因此可以看出线程之间的内存是独立的。

启动

线程的启动方法如下:

void Test::StartThread() {
	ThreadObject * thread = new ThreadObject();
	thread->start();
}

QRunnable

创建

QRunnable是所有可执行对象的基类,继承QRunnable类后重写其中的run()函数,即可实现线程开发。虽然基本步骤和QThread的做法一致。但是,QRunnable不能自己运行,而是必须借助于QThreadPool类运行。

// RunnableObject.h
#pragma once

#include <QObject>
#include <QThread>
#include <QRunnable>

class RunnableObject
    : public QObject
    , public QRunnable
{
    Q_OBJECT
public:
    RunnableObject();
    ~RunnableObject();
    virtual void run() override;
public slots:
    void StopThread();
private:
    bool            is_stop_;
    int             count_;
};
// RunnableObject.cpp
#include "RunnableObject.h"
#include <QDebug>

RunnableObject::RunnableObject() { }

RunnableObject::~RunnableObject() = default;

void RunnableObject::run()
{
    is_stop_ = false;
    count_ = 0;
    while (!is_stop_) {
        qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Count: " << ++count_;
        QThread::sleep(3);
    }
    qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Exit";
}

void RunnableObject::StopThread()
{
    is_stop_ = true;
}

启动

线程的启动方法如下:

void Test::StartThread() {
	QThreadPool * thread_pool = new ThreadObject();
	thread->start(new RunnableObject());
}

moveToThread

创建

所有继承了QObject的类都可以使用moveToThread()函数将自己的功能放入到线程中运行。

// MoveObject.h
#pragma once

#include <QObject>
#include <QThread>
#include <QDebug>

class MoveObject
    : public QObject
{
    Q_OBJECT
public:
    MoveObject();
    ~MoveObject();
public slots:
    void StopThread();
    void DoWorks(); 
private:
    bool        is_stop_;
    int         count_;
};
// MoveObject.cpp
#include "MoveObject.h"

MoveObject::MoveObject() { }

MoveObject::~MoveObject() = default;

void MoveObject::StopThread()
{
    is_stop_ = true;
}

void MoveObject::DoWorks()
{
    is_stop_ = false;
    count_ = 0;
    while (!is_stop_) {
        qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Count: " << ++count_;
        QThread::sleep(3);
    }
    qInfo() << "Thread-ID: " << QThread::currentThreadId() << " Exit";
}

启动

线程的运行代码:

void Test::StartThread() {
	MoveObject * move = new MoveObject();
	QThread * move_thread = new QThread();
	move->moveToThread(move_thread);
	connect(move_thread, &QThread::started, move, &MoveObject::DoWorks);
	move_thread->start();
}

在使用这种线程启动方式时需要注意一点,线程QThread类的生命周期一定要长于工作类。因此安全的方式就是全都使用new以确保生命周期是一致的。

  • 27
    点赞
  • 161
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值