Qt开发:如何使用QThread
文章目录
- 一、QThread 的基本概念
- 二、QThread中的常用成员函数
- 三、QThread的信号和槽函数
- 四、QThread的两种使用方法
一、QThread 的基本概念
QThread 是 Qt 框架中用于多线程编程的类。它允许我们在应用程序中创建和管理线程,从而在后台执行耗时操作,避免阻塞主线程(通常是 GUI 线程),保持用户界面的响应性。
线程与主线程:
- 主线程通常负责处理用户界面和事件循环。
- 子线程用于执行耗时操作,如文件 I/O、网络请求、复杂计算等。
QThread 的作用:
- QThread 提供了一个平台无关的方式来管理线程。
- 它封装了底层操作系统的线程 API,使得线程的创建、启动、停止和管理更加方便。
QThread 的工作方式:
- QThread 本身并不是线程,而是一个线程管理类。
- 可以通过继承 QThread 并重写 run() 方法来定义线程的执行逻辑。
- 或者可以将 QObject 移动到 QThread 中,利用信号和槽机制来执行任务。
二、QThread中的常用成员函数
1.QThread::exit
用于结束线程的事件循环并指定一个返回码。这个函数通常用于控制线程的退出行为,尤其是在使用事件循环的线程中。
函数原型:
void QThread::exit(int returnCode = 0)
功能:
结束线程的事件循环,并设置线程的返回码。调用此函数后,线程的事件循环会退出,线程的执行会从 QThread::exec() 返回。
参数:
returnCode:线程的返回码,默认为 0。这个值可以通过 QThread::exec() 的返回值获取。
使用场景:
当你希望线程在某个条件下退出事件循环时,可以调用此函数。通常与QThread::exec() 配合使用。
以下是一个简单的示例,展示如何使用 QThread::exit() 来结束线程的事件循环。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 启动事件循环
int returnCode = exec();
qDebug() << "Thread exited with return code:" << returnCode;
}
public slots:
void stopThread() {
qDebug() << "Stopping thread...";
exit(42); // 结束事件循环,并设置返回码为 42
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
// 使用 QTimer 在 2 秒后停止线程
QTimer::singleShot(2000, &thread, &WorkerThread::stopThread);
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 事件循环的必要性:exit() 函数仅对调用 exec() 启动事件循环的线程有效。如果线程没有事件循环,调用 exit() 不会有任何效果。
- 线程安全:exit() 是线程安全的,可以从任何线程调用。
- 返回码的作用:返回码可以用于传递线程的退出状态。例如,0 通常表示成功,非零值表示错误或特定状态。
- 与 quit() 的区别:exit() 和 quit() 的功能类似,但 exit() 可以指定返回码,而 quit() 的返回码固定为 0。
2.QThread::isFinished()
函数原型:
bool QThread::isFinished() const
功能:
返回线程是否已经结束。如果线程已经完成执行,则返回 true;否则返回 false。
参数:
true:线程已经结束。false:线程仍在运行。
使用场景:
在需要等待线程完成时,可以使用此函数检查线程状态。在需要根据线程状态执行特定操作时,可以使用此函数进行判断。
以下是一个简单的示例,展示如何使用 isFinished() 检查线程是否结束。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 模拟耗时操作
sleep(3);
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
// 检查线程是否结束
while (!thread.isFinished()) {
qDebug() << "Thread is still running...";
QThread::sleep(1); // 主线程等待 1 秒
}
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:·
- 线程状态检查:isFinished() 是一个非阻塞函数,可以随时调用以检查线程状态。
- 与 wait() 的区别:isFinished() 仅检查线程状态,不会阻塞当前线程。wait() 会阻塞当前线程,直到目标线程结束。
- 线程安全:isFinished() 是线程安全的,可以从任何线程调用。
- 线程结束的条件:线程结束的条件是 run() 方法执行完毕或调用了 QThread::exit() 或 QThread::quit()。
3.QThread::isInterruptionRequested()
用于检查当前线程是否被请求中断。这个函数通常用于实现线程的优雅退出机制,允许线程在执行任务时定期检查中断请求,并在适当的时候安全地终止。
函数原型:
bool QThread::isInterruptionRequested() const
功能:
返回线程是否被请求中断。如果线程的中断标志被设置(通过 QThread::requestInterruption()),则返回 true;否则返回 false。
返回值:
true:线程的中断标志被设置,表示线程被请求中断。false:线程的中断标志未被设置,表示线程可以继续运行。
使用场景:
在线程的 run() 方法中定期检查中断请求,以实现线程的优雅退出。在需要长时间运行的任务中,提供一种机制来安全地终止线程。
以下是一个简单的示例,展示如何使用 isInterruptionRequested() 实现线程的优雅退出。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
for (int i = 0; i < 10; ++i) {
// 检查中断请求
if (isInterruptionRequested()) {
qDebug() << "Thread interrupted, exiting...";
return; // 退出线程
}
qDebug() << "Working on task" << i;
sleep(1); // 模拟耗时操作
}
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
// 使用 QTimer 在 3 秒后请求中断线程
QTimer::singleShot(3000, [&thread]() {
qDebug() << "Requesting thread interruption...";
thread.requestInterruption(); // 请求中断线程
});
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 中断请求的检查:isInterruptionRequested() 是一个非阻塞函数,可以在线程的任何地方调用。建议在耗时操作或循环中定期检查中断请求,以确保线程能够及时响应中断。
- 中断请求的设置:中断请求通过 QThread::requestInterruption() 设置。中断请求是一个标志,不会强制终止线程,线程需要主动检查并退出。
- 线程安全:isInterruptionRequested() 和 requestInterruption() 都是线程安全的,可以从任何线程调用。
- 与 exit() 和 quit() 的区别:isInterruptionRequested() 和 requestInterruption() 提供了一种更灵活的线程退出机制,允许线程在适当的时候安全地退出。exit() 和 quit()
用于结束线程的事件循环,适用于使用 exec() 的线程。
4.QThread::isRunning()
用于检查线程是否正在运行。这个函数在多线程编程中非常有用,尤其是在需要监控线程状态或确保线程正确启动的场景中。
函数原型:
bool QThread::isRunning() const
功能:
返回线程是否正在运行。如果线程已经启动(即调用了 start())但尚未结束,则返回 true;否则返回 false。
返回值:
true:线程正在运行。false:线程未运行(可能是未启动、已结束或被终止)。
使用场景:
在启动线程后,检查线程是否成功运行。在需要监控线程状态时,使用此函数判断线程是否仍在运行。在需要等待线程完成时,结合循环使用此函数。
以下是一个简单的示例,展示如何使用 isRunning() 检查线程的运行状态。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 模拟耗时操作
sleep(5);
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
// 检查线程是否正在运行
if (thread.isRunning()) {
qDebug() << "Thread is running!";
}
// 等待线程结束
while (thread.isRunning()) {
qDebug() << "Waiting for thread to finish...";
QThread::sleep(1); // 主线程等待 1 秒
}
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 线程状态的准确性:isRunning() 返回 true 仅表示线程已经启动且尚未结束。它不会区分线程是否正在执行任务或处于空闲状态。
- 与 isFinished() 的区别:isRunning() 返回 true 表示线程正在运行。isFinished() 返回 true 表示线程已经结束。
- 线程安全:isRunning() 是线程安全的,可以从任何线程调用。
- 线程启动的延迟:调用 start() 后,线程可能不会立即运行。如果需要确保线程已经开始运行,可以结合 QThread::msleep() 或事件循环进行检查。
5.QThread::loopLevel()
用于获取当前线程的事件循环嵌套级别。事件循环嵌套级别表示当前线程中有多少层事件循环正在运行。这个函数在需要调试或监控事件循环行为时非常有用。
函数原型:
int QThread::loopLevel() const
功能:
返回当前线程的事件循环嵌套级别。如果线程没有事件循环,则返回 0。
返回值:
- 返回一个整数,表示事件循环的嵌套级别。
- 0:当前线程没有事件循环。
- 1:当前线程有一个事件循环。
- n:当前线程有 n 层嵌套的事件循环。
事件循环嵌套级别
事件循环嵌套级别是指在一个线程中,事件循环被嵌套调用的次数。例如:
- 单层事件循环:调用 QCoreApplication::exec() 启动一个事件循环。此时 loopLevel() 返回 1。
- 嵌套事件循环:在事件循环中调用 QEventLoop::exec() 启动另一个事件循环。此时 loopLevel() 返回 2。
- 退出事件循环:每次调用 QEventLoop::quit() 或 QCoreApplication::exit() 会退出最内层的事件循环。退出后,loopLevel() 的值会减少。
以下是一个简单的示例,展示如何使用 loopLevel() 检查事件循环的嵌套级别。
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QEventLoop>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
// 获取当前线程
QThread *currentThread = QThread::currentThread();
// 打印初始事件循环嵌套级别
qDebug() << "Initial loop level:" << currentThread->loopLevel();
// 启动主事件循环
QTimer::singleShot(1000, []() {
qDebug() << "Main event loop started";
});
// 嵌套事件循环
QEventLoop nestedLoop;
QTimer::singleShot(2000, &nestedLoop, &QEventLoop::quit); // 2 秒后退出嵌套事件循环
qDebug() << "Starting nested event loop...";
nestedLoop.exec(); // 启动嵌套事件循环
qDebug() << "Nested event loop finished";
// 打印当前事件循环嵌套级别
qDebug() << "Current loop level:" << currentThread->loopLevel();
return app.exec();
}
输出结果:
6.QThread::priority()
用于获取线程的优先级。线程优先级决定了操作系统调度线程的顺序,优先级较高的线程会更频繁地获得 CPU 时间片。
函数原型:
QThread::Priority QThread::priority() const
功能:
返回当前线程的优先级。
返回值:
返回一个 QThread::Priority 枚举值,表示线程的优先级。可能的取值包括:
- QThread::IdlePriority:最低优先级,仅在系统空闲时运行。
- QThread::LowestPriority
- QThread::LowPriority
- QThread::NormalPriority:默认优先级。
- QThread::HighPriority
- QThread::HighestPriority
- QThread::TimeCriticalPriority:最高优先级,几乎实时运行。
- QThread::InheritPriority:继承创建线程的优先级(默认值)。
使用场景:
在需要控制线程调度行为时,获取线程的优先级。调试或监控线程的优先级设置。
设置线程优先级
与 priority() 相关的另一个函数是 void QThread::setPriority(QThread::Priority priority),用于设置线程的优先级。
函数原型:
void QThread::setPriority(QThread::Priority priority)
参数:
priority:要设置的优先级,取值为 QThread::Priority 枚举值。
注意事项:
- 必须在线程启动之前设置优先级。如果线程已经运行,调用 setPriority() 不会有任何效果。
- 优先级的具体行为取决于操作系统。不同操作系统对优先级的实现可能有所不同。
以下是一个简单的示例,展示如何使用 priority() 和 setPriority() 获取和设置线程的优先级。
#include <QThread>
#include <QDebug>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread is running with priority:" << priority();
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
// 设置线程优先级
thread.setPriority(QThread::HighPriority);
// 获取线程优先级
qDebug() << "Thread priority before start:" << thread.priority();
// 启动线程
thread.start();
// 等待线程结束
thread.wait();
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 优先级的设置时机:必须在调用 start() 之前设置优先级。如果线程已经运行,setPriority() 不会生效。
- 操作系统的差异:不同操作系统对线程优先级的实现可能不同。例如,某些操作系统可能不支持所有优先级级别,或者将多个优先级映射到同一个级别。
- 优先级的实际效果:优先级较高的线程会更频繁地获得 CPU 时间片,但并不能保证绝对的执行顺序。实际效果还取决于操作系统的调度策略。
- 默认优先级:如果没有显式设置优先级,线程的默认优先级是 QThread::InheritPriority,即继承创建线程的优先级。
7.QThread::setStackSize()
用于设置线程的堆栈大小。堆栈大小是线程运行时使用的内存空间,用于存储局部变量、函数调用信息等。合理设
函数原型:
void QThread::setStackSize(uint stackSize)
功能:
设置线程的堆栈大小(以字节为单位)。
参数:
stackSize:堆栈大小(以字节为单位)。如果设置为 0,则使用操作系统的默认堆栈大小。
使用场景:
- 当线程需要处理大量递归调用或大型局部变量时,可能需要增加堆栈大小。
- 在嵌入式系统或内存受限的环境中,可能需要减少堆栈大小以节省内存。
以下是一个简单的示例,展示如何使用 setStackSize() 设置线程的堆栈大小。
#include <QThread>
#include <QDebug>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread is running with stack size:" << stackSize();
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
// 设置线程堆栈大小为 2 MB(2 * 1024 * 1024 字节)
thread.setStackSize(2 * 1024 * 1024);
// 获取线程堆栈大小
qDebug() << "Thread stack size before start:" << thread.stackSize();
// 启动线程
thread.start();
// 等待线程结束
thread.wait();
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 设置堆栈大小的时机:必须在调用 start() 之前设置堆栈大小。如果线程已经运行,setStackSize() 不会生效。
- 堆栈大小的单位:stackSize 参数的单位是字节。例如,1 MB = 1024 * 1024 字节。
- 堆栈大小的限制:堆栈大小不能小于操作系统的最小限制。如果设置的值过小,操作系统可能会忽略或调整为最小允许值。堆栈大小也不能超过操作系统的最大限制。
- 默认堆栈大小:如果不设置堆栈大小,线程将使用操作系统的默认值。默认值通常足够大多数应用程序使用。
- 堆栈溢出的风险:如果堆栈大小设置过小,可能会导致堆栈溢出,引发程序崩溃。如果堆栈大小设置过大,可能会浪费内存资源。
8.Thread::wait()
用于阻塞当前线程,直到目标线程结束或超时。这个函数在多线程编程中非常有用,尤其是在需要等待线程完成或控制线程同步的场景中。
函数原型:
bool QThread::wait(unsigned long time = ULONG_MAX)
功能:
阻塞当前线程,直到目标线程结束或超时。
参数:
time:等待的时间(以毫秒为单位)。默认值为 ULONG_MAX,表示无限等待。
返回值:
true:目标线程已结束。false:等待超时,目标线程仍未结束。
使用场景:
- 在主线程中等待工作线程完成。
- 在需要控制线程同步时,使用此函数确保线程按预期顺序执行。
以下是一个简单的示例,展示如何使用 wait() 等待线程完成。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 模拟耗时操作
sleep(5);
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
qDebug() << "Main thread: waiting for worker thread to finish...";
// 等待线程完成,最多等待 10 秒
if (thread.wait(10000)) {
qDebug() << "Main thread: worker thread has finished.";
} else {
qDebug() << "Main thread: wait timed out, worker thread is still running.";
}
return 0;
}
输出结果:
注意事项:
- 阻塞当前线程:wait() 会阻塞当前线程,直到目标线程结束或超时。因此,在主线程中调用 wait() 时,主线程会暂停执行。
- 超时设置:如果设置了超时时间,wait() 会在超时后返回 false,即使目标线程仍未结束。如果不设置超时时间(默认值 ULONG_MAX),wait() 会无限等待,直到目标线程结束。
- 线程状态检查:在调用 wait() 之前,可以使用 isRunning() 检查线程是否仍在运行。
- 线程安全:wait() 是线程安全的,可以从任何线程调用。
- 与 isFinished() 的区别:wait() 是阻塞函数,会暂停当前线程直到目标线程结束。isFinished() 是非阻塞函数,仅检查线程状态。
三、QThread的信号和槽函数
1.QThread::quit()
用于请求线程退出事件循环。这个函数通常用于结束使用事件循环的线程(即调用了 QThread::exec() 的线程)。调用 quit() 后,线程的事件循环会退出,线程的执行会从 exec() 返回。
函数原型:
void QThread::quit()
功能:
请求线程退出事件循环。如果线程没有运行事件循环,调用此函数不会有任何效果。
事件循环的必要性:
quit() 仅对调用 exec() 启动事件循环的线程有效。如果线程没有事件循环(例如直接重写 run() 方法而没有调用 exec()),调用 quit() 不会有任何效果。
以下是一个简单的示例,展示如何使用 quit() 结束线程的事件循环。
#include <QThread>
#include <QDebug>
#include <QTimer>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 启动事件循环
exec();
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start(); // 启动线程
// 使用 QTimer 在 3 秒后请求线程退出
QTimer::singleShot(3000, [&thread]() {
qDebug() << "Requesting thread to quit...";
thread.quit(); // 请求线程退出
});
// 等待线程结束
thread.wait();
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
2.QThread::start()
用于启动线程。调用 start() 后,线程会开始执行其 run() 方法中的代码。start() 是使用 QThread 进行多线程编程的核心函数之一。
功能:
启动线程,使其开始执行 run() 方法中的代码。
参数:
priority:线程的优先级,默认为 QThread::InheritPriority,表示继承创建线程的优先级。其他可选值包括:
- QThread::IdlePriority
- QThread::LowestPriority
- QThread::LowPriority
- QThread::NormalPriority
- QThread::HighPriority
- QThread::HighestPriority
- QThread::TimeCriticalPriority
使用场景:
- 在需要创建并启动新线程时,调用此函数。
- 在需要控制线程优先级时,可以通过 priority 参数设置。
线程的生命周期:
- 创建线程:通过继承 QThread 或创建 QThread 对象来定义线程。
- 启动线程:调用 start() 启动线程,线程开始执行 run() 方法。
- 线程运行:线程执行 run() 方法中的代码。
- 线程结束:当 run() 方法执行完毕或调用 QThread::exit() 时,线程结束。
以下是一个简单的示例,展示如何使用 start() 启动线程。
#include <QThread>
#include <QDebug>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread started";
// 模拟耗时操作
sleep(3);
qDebug() << "Thread finished";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
// 启动线程
qDebug() << "Starting thread...";
thread.start();
// 等待线程结束
thread.wait();
qDebug() << "Main thread: worker thread has finished.";
return 0;
}
输出结果:
注意事项:
- 线程启动的时机:必须在调用 start() 之前设置线程的优先级或堆栈大小。如果线程已经运行,这些设置不会生效。
- 线程优先级:可以通过 priority 参数设置线程的优先级。优先级较高的线程会更频繁地获得 CPU 时间片。
- 线程安全:start() 是线程安全的,可以从任何线程调用。
- 线程的生命周期:线程启动后,会执行 run() 方法中的代码。当 run() 方法执行完毕或调用 exit() 时,线程结束。
- 与 run() 的直接调用:不要直接调用 run() 方法,否则代码会在当前线程中执行,而不是在新线程中执行。始终使用 start() 启动线程。
3.QThread::terminate()
通常用于多线程编程。以下是关于 QThread::terminate() 的详细介绍和使用注意事项。
函数原型:
void QThread::terminate()
功能: 强制终止线程的执行。
行为:
调用 terminate() 会立即终止目标线程,无论线程当前处于什么状态。线程的终止是通过操作系统的线程终止机制实现的,因此线程可能在任何代码点被终止。
使用注意事项:
- 不推荐使用: terminate() 是一个危险的函数,通常不推荐使用。因为它会强制终止线程,可能导致资源泄漏、数据不一致或其他未定义行为。线程可能在持有锁、分配内存或执行其他关键操作时被终止,从而导致程序不稳定。
- 资源清理: 由于 terminate() 不会执行线程的析构函数或清理操作,因此可能会导致资源(如内存、文件句柄、锁等)无法正确释放。
- 替代方案: 通常情况下,更好的做法是通过信号和槽机制,或者设置一个标志位,让线程在安全的情况下自行退出。例如,可以在线程的 run() 函数中定期检查一个标志位,并在标志位为 true 时退出线程。
- 线程状态: 调用 terminate() 后,线程的状态会变为 QThread::Finished,但线程对象并不会被删除,除非它被显式地删除或设置为自动删除。
以下是一个简单的示例,展示了如何使用 QThread::terminate(),但请注意,这只是一个演示,实际应用中应尽量避免使用 terminate()。
#include <QThread>
#include <QDebug>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
while (!isInterruptionRequested()) {
qDebug() << "Working...";
sleep(1);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start();
// 让线程运行一段时间
QThread::sleep(5);
// 强制终止线程
qDebug() << "Terminating thread...";
thread.terminate();
thread.wait(); // 等待线程真正终止
qDebug() << "Thread terminated.";
return app.exec();
}
输出结果:
为了避免使用 terminate(),可以使用以下替代方案:
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
while (!isInterruptionRequested()) {
qDebug() << "Working...";
sleep(1);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
thread.start();
// 让线程运行一段时间
QThread::sleep(5);
// 请求线程中断
qDebug() << "Requesting thread interruption...";
thread.requestInterruption();
thread.wait(); // 等待线程自行退出
qDebug() << "Thread finished.";
return app.exec();
}
4.QThread::started()
QThread::started() 是 Qt 框架中 QThread 类的一个信号,用于在线程启动时发出通知。这个信号在多线程编程中非常有用,尤其是在需要在线程开始执行时执行某些初始化操作或与其他线程进行同步时。
信号介绍:
void QThread::started()
功能: 当线程开始运行时,started() 信号会被发射。
触发时机: 在线程的 run() 函数执行之前,started() 信号会被触发。
用途: 可以用于在线程启动时执行一些初始化操作,或者通知其他部分线程已经开始运行。
使用场景:
- 线程初始化: 在线程启动时执行一些初始化操作,例如分配资源、打开文件或建立网络连接。
- 线程同步: 通知主线程或其他线程,当前线程已经开始运行,可以用于同步操作。
- 状态监控: 监控线程的生命周期,确保线程按预期启动。
以下是一个简单的示例,展示了如何使用 QThread::started() 信号。
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread is running...";
// 模拟工作
for (int i = 0; i < 5; ++i) {
qDebug() << "Working..." << i;
sleep(1);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
// 连接 started() 信号到槽函数
QObject::connect(&thread, &QThread::started, []() {
qDebug() << "Thread started!";
});
// 启动线程
thread.start();
// 等待线程完成
thread.wait();
qDebug() << "Thread finished.";
return app.exec();
}
输出结果:
5.QThread::finished()
QThread::finished 是 QThread 类的一个信号,用于在线程完成执行时发出通知。这个信号在多线程编程中非常有用,尤其是在需要在线程结束时执行清理操作或与其他线程进行同步时。
信号介绍:
void QThread::finished()
功能: 当线程完成执行时,finished() 信号会被发射。
触发时机: 在线程的 run() 函数执行完毕后,finished() 信号会被触发。
用途: 可以用于在线程结束时执行一些清理操作,或者通知其他部分线程已经完成运行。
使用场景:
- 资源清理: 在线程结束时释放资源,例如关闭文件、释放内存或断开网络连接。
- 线程同步: 通知主线程或其他线程,当前线程已经完成运行,可以用于同步操作。
- 状态监控: 监控线程的生命周期,确保线程按预期结束。
以下是一个简单的示例,展示了如何使用 QThread::finished 信号。
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "Thread is running...";
// 模拟工作
for (int i = 0; i < 5; ++i) {
qDebug() << "Working..." << i;
sleep(1);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
// 连接 finished() 信号到槽函数
QObject::connect(&thread, &QThread::finished, []() {
qDebug() << "Thread finished!";
});
// 启动线程
thread.start();
// 等待线程完成
thread.wait();
qDebug() << "Main thread continues...";
return app.exec();
}
输出结果:
四、QThread的两种使用方法
在 Qt 中,QThread 是用于多线程编程的核心类。QThread 的使用方法主要有两种:
- 继承 QThread 并重写 run() 方法:这是传统的使用方法,适用于需要完全控制线程执行逻辑的场景。
- 使用 QObject 和 moveToThread():这是更推荐的使用方法,利用 Qt 的信号与槽机制,将工作对象移动到线程中执行,更适合事件驱动的编程模型。
方法 1:继承 QThread 并重写 run()
特点:
- 直接继承 QThread,并重写 run() 方法。
- run() 方法是线程的入口点,线程启动后会执行 run() 中的代码。
- 适合需要完全控制线程执行逻辑的场景。
示例代码:
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
class WorkerThread : public QThread
{
Q_OBJECT
protected:
void run() override {
qDebug() << "WorkerThread: Thread started!";
// 模拟工作
for (int i = 0; i < 5; ++i) {
qDebug() << "Working..." << i;
sleep(1); // 模拟耗时操作
}
qDebug() << "WorkerThread: Thread finished!";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
WorkerThread thread;
qDebug() << "Main thread: Starting worker thread...";
thread.start(); // 启动线程
qDebug() << "Main thread: Waiting for worker thread to finish...";
thread.wait(); // 等待线程完成
qDebug() << "Main thread: Worker thread finished, application exiting...";
return app.exec();
}
方法 2:使用 QObject 和 moveToThread()
特点:
- 创建一个 QObject 派生类作为工作对象,并将其移动到 QThread 中。
- 使用信号与槽机制实现线程间的通信。
- 适合需要事件循环的场景(如定时器、网络请求等)。
示例代码:
#include <QThread>
#include <QDebug>
#include <QCoreApplication>
#include <QTimer>
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
qDebug() << "Worker: Doing work..." << QThread::currentThreadId();
// 模拟工作
for (int i = 0; i < 5; ++i) {
qDebug() << "Working..." << i;
QThread::sleep(1); // 模拟耗时操作
}
qDebug() << "Worker: Work finished!";
emit workFinished();
}
signals:
void workFinished();
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "main:" << QThread::currentThreadId();
QThread thread;
Worker worker;
// 将 worker 移动到新线程
worker.moveToThread(&thread);
// 连接线程启动信号到 worker 的槽函数
QObject::connect(&thread, &QThread::started, &worker, &Worker::doWork);
// 连接 worker 的完成信号到线程的退出槽函数
QObject::connect(&worker, &Worker::workFinished, &thread, &QThread::quit);
// 连接线程完成信号到 worker 的删除槽函数
QObject::connect(&thread, &QThread::finished, &worker, &QObject::deleteLater);
qDebug() << "Main thread: Starting worker thread...";
thread.start(); // 启动线程
qDebug() << "Main thread: Waiting for worker thread to finish...";
thread.wait(); // 等待线程完成
qDebug() << "Main thread: Worker thread finished, application exiting...";
return app.exec();
}
输出结果: