在正常情况下线程的生命周期,首先是创建一个线程对象,设置一些线程参数,例如,名字和优先级之类的,这是第一步。然后调用start()方法,这时线程并不会真正开始运行了,此时,只是准备就绪阶段,表示线程可以运行了,但是还没有开始运行。没有开始是因为在等待抢占到CPU的执行权限,一旦获得了执行权限就会开始执行执行run()方法的内容,直到run()方法退出了或者调用了中断后线程才会停止,如下图所示:
上图中描述的是单个线程,随着线程的增加线程的生命周期会有很多变化,如下图所示:
运行状态中如果使用了sleep()或者wait()等让线程暂停的函数,就会进入阻塞状态,这个状态什么都不做,线程会停在这里。当sleep()的时间到了或者收到了相应的notify()通知时,线程会再次进入就绪状态,等待获取CPU的执行权限。正在执行的线程其执行权限被其他线程抢占了则再次返回就绪状态,多个线程正常运行情况下会一直在就绪和运行两个状态来回切换。
在Qt中继承QThread是常规的实现线程的方式,只需要继承后重写其中的run()函数
(大多数线程操作都是重写run()函数)并实现自己的线程工作即可。
// ThreadObject.h
#pragma once
#include
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
#include
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";
}
在上面的代码中ThreadObject
继承了QThread
并重写了run()方法
,每次点击创建按钮都会创建一个新的线程并在run()函数
中每隔3秒打印一次,而且在个线程中的计数变量互相之间并不影响,因此可以看出线程之间的内存是独立的。
线程的启动方法如下:
void Test::StartThread() {
ThreadObject * thread = new ThreadObject();
thread->start();
}
QRunnable是所有可执行对象的基类,继承QRunnable类后重写其中的run()函数
,即可实现线程开发。虽然基本步骤和QThread的做法一致。但是,QRunnable不能自己运行,而是必须借助于QThreadPool
类运行。
// RunnableObject.h
#pragma once
#include
#include
#include
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
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());
}
所有继承了QObject的类都可以使用moveToThread()
函数将自己的功能放入到线程中运行。
// MoveObject.h
#pragma once
#include
#include
#include
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
以确保生命周期是一致的。