QThread 类
QThread 类提供了一种平台无关的方式来管理线程。更多...
头文件 | #include <QThread> |
CMake | find_package(Qt6 REQUIRED COMPONENTS Core) target_link_libraries(mytarget PRIVATE Qt6::Core) |
qmake | QT += core |
继承 | QObject |
- 所有成员的列表,包括继承的成员
- QThread 是 多线程类 的一部分。
公共类型
枚举 | Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, HighPriority, …, InheritPriority } |
公共函数
QThread(QObject *parent = nullptr) | |
虚拟 | ~QThread() |
QAbstractEventDispatcher * | eventDispatcher() const |
bool | isFinished() const |
bool | isInterruptionRequested() const |
bool | isRunning() const |
int | loopLevel() const |
QThread::Priority | priority() const |
void | requestInterruption() |
void | setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) |
void | setPriority(QThread::Priority priority) |
void | setStackSize(uint stackSize) |
uint | stackSize() const |
bool | wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)) |
bool | wait(unsigned long time) |
重实现公共函数
虚拟 bool | event(QEvent *event) override |
公共槽
void | exit(int returnCode = 0) |
void | quit() |
void | start(QThread::Priority priority = InheritPriority) |
void | terminate() |
信号
静态公共成员
QThread * | create(Function &&f, Args &&... args) |
QThread * | currentThread() |
Qt::HANDLE | currentThreadId() |
int | idealThreadCount() |
void | msleep(unsigned long msecs) |
void | sleep(unsigned long secs) |
(since 6.6) void | sleep(std::chrono::nanoseconds nsecs) |
void | usleep(unsigned long usecs) |
void | yieldCurrentThread() |
受保护的函数
静态受保护成员
void | setTerminationEnabled(bool enabled = true) |
详细描述
QThread对象管理程序中的一个控制线程。QThread通过调用run()开始执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内部运行Qt事件循环。
您可以通过使用QObject::moveToThread()将工作对象移动到线程来使用工作对象。
class Worker : public QObject { Q_OBJECT public slots: void doWork(const QString ¶meter) { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); } signals: void resultReady(const QString &result); }; class Controller : public QObject { Q_OBJECT QThread workerThread; public: Controller() { Worker *worker = new Worker; worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &Controller::operate, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &Controller::handleResults); workerThread.start(); } ~Controller() { workerThread.quit(); workerThread.wait(); } public slots: void handleResults(const QString &); signals: void operate(const QString &); };
然后,工作槽内的代码将在另一个线程中执行。但是,您可以连接工作对象的槽到任何对象、任何线程的信号。由于一个称为排队的信号连接的机制,跨线程连接信号和槽是安全的。
使代码在单独的线程中运行的另一种方法是从QThread派生类并重写run()。例如
class WorkerThread : public QThread { Q_OBJECT void run() override { QString result; /* ... here is the expensive or blocking operation ... */ emit resultReady(result); } signals: void resultReady(const QString &s); }; void MyObject::startWorkInAThread() { WorkerThread *workerThread = new WorkerThread(this); connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults); connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater); workerThread->start(); }
在那个例子中,当运行函数返回时,线程将退出。除非调用exec(),否则线程中不会有事件循环运行。
需要记住的是,QThread实例存活在创建它的旧线程中,而不是调用run()的新线程中。这意味着QThread的所有队列插槽和调用方法都将在此旧线程中执行。因此,希望在新线程中调用槽的开发者必须使用工作对象方法;不应该直接在派生的QThread中实现新槽。
与排队槽或调用方法不同,直接在QThread对象上调用的方法将在调用该方法的线程中执行。当从QThread派生类时,请注意构造函数在旧线程中执行,而run()在新的线程中执行。如果从两个函数中都访问了成员变量,那么变量将从两个不同的线程中访问。请检查这样做是否安全。
注意:在与其他线程中的对象交互时必须谨慎。作为一个通用规则,函数只能从创建QThread对象的线程本身调用(例如,setPriority),除非文档另有说明。有关详细信息,请参阅线程同步。
线程管理
当线程开始()或完成()时,QThread会通过信号通知您,或者您可以使用isFinished()和isRunning()来查询线程的状态。
您可以通过调用exit()或quit()来停止线程。在极端情况下,您可能需要强制终止()正在执行的线程。但是,这样做是非常危险的,也是不推荐的。请参阅terminate()和setTerminationEnabled()的文档以获取详细信息。
通常,当线程结束时,您希望处理驻留在线程中的对象。为此,将finished()信号连接到QObject::deleteLater。
使用 wait() 函数将调用线程阻塞,直到另一个线程执行完毕(或直到指定的超时时间到达)。
QThread 还提供了静态、平台无关的 sleep 函数:sleep(),msleep(),和 usleep() 分别提供了秒、毫秒和微秒的完整分辨率。
注意:通常情况下,wait() 和 sleep() 函数并不必要,因为 Qt 是一个事件驱动框架。而不是使用 wait(),可以考虑监听 finished() 信号。而不是使用 sleep() 函数,可以考虑使用 QTimer。
静态函数 currentThreadId() 和 currentThread() 分别返回当前正在执行的线程标识符。前者返回一个与平台相关的线程 ID;后者返回一个 QThread 指针。
要选择你的线程将被赋予的名称(例如,在 Linux 上通过 ps -L
命令识别),可以在启动线程之前调用 setObjectName()。如果不调用 setObjectName(),则分配给你的线程的名称将是你线程对象运行时类型的类名(例如,在 Mandelbrot 示例中为 "RenderThread"
,因为这是 QThread 子类的名称)。请注意,这目前在 Windows 的发布构建中不可用。
另请参阅:Qt 中的线程支持,QThreadStorage,同步线程,Mandelbrot,使用信号量生产者和消费者,以及 使用等待条件的生产者和消费者。
成员类型文档
枚举 QThread::Priority
此类枚举表示操作系统应如何安排新创建的线程。
常量 | 值 | 描述 |
---|---|---|
QThread::IdlePriority | 0 | 仅在没有其他线程运行时才安排。 |
QThread::LowestPriority | 1 | 比 LowPriority 安排得更少。 |
QThread::LowPriority | 2 | 比 NormalPriority 安排得更少。 |
QThread::NormalPriority | 3 | 操作系统默认优先级。 |
QThread::HighPriority | 4 | 比 NormalPriority 安排得更频繁。 |
QThread::HighestPriority | 5 | 比 HighPriority 安排得更频繁。 |
QThread::TimeCriticalPriority | 6 | 尽可能多地安排。 |
QThread::InheritPriority | 7 | 使用与创建该线程相同的优先级。这是默认值。 |
成员函数文档
[显式]
QThread::QThread(QObject *parent = nullptr)
构建一个新的 QThread 来管理新线程。分发 parent 拥有 QThread。该线程只有在调用 start() 之前不会开始执行。
另请参阅:start()。
[虚 noop]
QThread::~QThread()
销毁 QThread。
请注意,删除 QThread 对象不会停止它所管理的线程的执行。删除正在执行的 QThread(即 isFinished() 返回 false
)会导致程序崩溃。在删除 QThread 之前,等待 finished() 信号。
从Qt 6.3开始,即使在相应线程仍在运行的情况下,也可以删除使用QThread :: create() 调用创建的QThread 实例。在这种情况下,Qt会向该线程发送中断请求(通过requestInterruption());将要求线程的事件循环(如果有的话)退出(通过quit());并将阻塞,直到线程完成。
另请参阅create(),isInterruptionRequested(),exec(),以及 quit。
[静态]
模板 <typename Function, typename... Args> QThread *QThread::create(Function &&f, Args &&... args)
创建一个新的 QThread 对象,该对象将使用参数 args 执行函数 f。
新线程不会启动 - 必须通过显式调用 start() 来启动。这样您可以连接到其信号,将 QObjects 移到线程,选择新线程的优先级等。函数 f 将在新线程中调用。
返回新创建的 QThread 实例。
注意:调用者将获取返回的 QThread 实例的所有权。
另请参阅:start()。
[静态]
QThread *QThread::currentThread()
返回管理当前执行线程的 QThread 指针。
[静态 noexcept]
Qt::HANDLE QThread::currentThreadId()
返回当前执行线程的线程句柄。
警告:此函数返回的句柄用于内部目的,不应在任何应用程序代码中使用。
注意:在 Windows 上,此函数返回Win32函数 GetCurrentThreadId() 返回的 DWORD(Windows 线程 ID),而不是 Win32 函数 GetCurrentThread() 返回的伪句柄(Windows 线程句柄)。
[覆盖虚拟]
bool QThread::event(QEvent *event)
重新实现: QObject::event(QEvent *e)。
QAbstractEventDispatcher *QThread::eventDispatcher() const
返回线程的事件分配器对象的指针。如果没有为线程创建事件分配器,则此函数返回 nullptr
。
另请参阅setEventDispatcher。
[受保护]
int QThread::exec()
进入事件循环并等待直到 exit() 调用,返回传递给 exit() 的值。如果通过 quit() 调用 exit(),则返回值为 0。
此函数应从 run() 内调用。调用此函数是必要的,以便开始事件处理。
注意: 该函数只能在当前线程中调用,即当前线程。
[slot]
void QThread::exit(int returnCode = 0)
告诉线程的事件循环以指定的返回码退出。
调用此函数后,线程将离开事件循环,并从对 QEventLoop::exec() 的调用返回。函数 QEventLoop::exec() 返回 returnCode。
根据惯例,返回码为 0 表示成功,任何非零值表示错误。
请注意,与同名的 C 库函数不同,此函数 确实 返回给调用者 - 停止的是事件处理。
在此线程中,除非再次调用 QThread::exec(),否则将不再启动任何 QEventLoops。如果 QThread::exec() 中的事件循环没有运行,则下一个对 QThread::exec() 的调用也将立即返回。
注意: 此函数是 线程安全。
另请参阅 quit() 和 QEventLoop。
[private signal]
void QThread::finished()
此信号由相关线程在执行完成前发出。
当此信号发出时,事件循环已经停止运行。除了延迟删除事件之外,线程中将不再处理任何更多的事件。此信号可以连接到 QObject::deleteLater(),以释放该线程中的对象。
注意: 如果使用 terminate() 终止了相关线程,则发出此信号时的线程来源是未定义的。
注意: 这是一个私有信号。它可以在信号连接中使用,但不能由用户发出。
另请参阅 started。
[static noexcept]
int QThread::idealThreadCount()
返回此进程可以并行运行的理想线程数。这是通过查询此进程可用的逻辑处理器数量(如果此操作系统支持)或系统中的逻辑处理器总数来完成的。如果无法确定这两个值中的任何一个,此函数返回 1。
注意: 在支持将线程的亲和度设置到所有逻辑处理器子集的操作系统上,该函数返回的值可能会在线程和时间之间变化。
注意: 在支持 CPU 热插拔和热卸载的操作系统上,该函数返回的值也可能随时间变化(请注意,可以通过软件打开和关闭 CPU,而无需进行物理的、硬件上的更改)。
bool QThread::isFinished() const
如果线程已完成则返回 true
;否则返回 false
。
注意: 此函数是 线程安全。
另请参阅 isRunning。
bool QThread::isInterruptionRequested() const
如果应停止在此线程上运行的任务,则返回 true。可以通过 requestInterruption() 请求中断。
此函数可用于使长时间运行的任务可干净中断。永不检查或对返回的值采取行动是安全的,但是建议在长时间运行函数中定期这样做。请注意,不要过多地调用它,以保持开销低。
void long_task() { forever { if ( QThread::currentThread()->isInterruptionRequested() ) { return; } } }
注意: 该函数只能在当前线程中调用,即当前线程。
另请参阅 currentThread() 和 requestInterruption()。
bool QThread::isRunning() const
如果线程正在运行,则返回 true
;否则返回 false
。
注意: 此函数是 线程安全。
另请参阅 isFinished()。
int QThread::loopLevel() const
返回线程当前的事件循环级别。
注意: 该函数只能在当前线程中调用,即当前线程。
[静态]
void QThread::msleep(unsigned long msecs)
这是一个重载函数,等同于调用
QThread::sleep(std::chrono::milliseconds{msecs});
注意: 此函数不保证精度。在重负载条件下,应用程序可能会比 msecs 多睡的时间。某些操作系统可能会将 msecs 四舍五入到 10 毫秒或 15 毫秒。
QThread::Priority QThread::priority() const
返回正在运行的线程的优先级。如果线程未运行,则此函数返回 InheritPriority
。
另请参阅 Priority、setPriority 和 start。
[槽]
void QThread::quit()
告诉线程的事件循环以返回码 0(成功)退出。等同于调用 QThread::exit(0)。
如果线程没有事件循环,此函数将不执行任何操作。
注意: 此函数是 线程安全。
另请参阅 exit() 和 QEventLoop。
void QThread::requestInterruption()
请求中断线程。该请求是咨询性的,由运行在线程上的代码决定是否及如何对此请求采取行动。此函数不会停止在线程上运行的任何事件循环,也不会以任何方式终止它。
注意: 此函数是 线程安全。
另请参阅 isInterruptionRequested()。
[虚受保护]
void QThread::run()
线程的起点。在调用 start() 之后,新创建的线程调用此函数。默认实现简单调用 exec()。
您可以重写此函数以简化高级线程管理。从此方法返回将结束线程的执行。
void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
将线程的事件调度器设置为 eventDispatcher。只有在线程还没有安装事件调度器的情况下才能这样做。
当创建 QCoreApplication 时为主线程自动创建事件调度器,对于辅助线程在 start() 上。
此方法将获取对象所有权。
另请参阅 eventDispatcher().
void QThread::setPriority(QThread::Priority priority)
此函数设置正在运行的线程的优先级。如果线程未运行,此函数将不执行任何操作并立即返回。使用start()以特定优先级启动线程。
优先级参数可以是QThread::Priority
枚举中的任何值,但不能是InheritPriority
。
优先级参数的效果取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上(如Linux,请参阅http://linux.die.net/man/2/sched_setscheduler以获得更多详细信息),将忽略优先级。
另请参阅 Priority、priority()和start().
void QThread::setStackSize(uint stackSize)
将线程的堆栈大小设置为stackSize。如果stackSize为零,操作系统或运行时将选择默认值。否则,线程的堆栈大小将是提供的值(该值可能被向上或向下取整)。
在大多数操作系统上,最初用于服务堆栈的内存量将小于stackSize,并且在线程使用堆栈时将增长。此参数设置它将被允许增长到的最大大小(即,它设置堆栈被允许占用的虚拟内存空间的大小)。
此函数必须在启动线程之前调用。
注意: 大多数操作系统对线程堆栈大小设置最小和最大限制。如果堆栈大小超出了这些限制,线程将无法启动。
另请参阅 stackSize().
[静态保护]
void QThread::setTerminationEnabled(bool enabled = true)
根据enabled参数启用或禁用当前线程的终止。线程必须由QThread启动。
当enabled为false时,禁用终止。将来的对QThread::terminate()的调用将立即返回,不起作用。相反,终止将推迟到终止被启用。
当enabled为true时,启用终止。将来的对QThread::terminate()的调用将正常终止线程。如果终止已被推迟(即QThread::terminate()在终止被禁用时调用),则此函数将立即终止调用线程。请注意,在这种情况下,此函数将不会返回。
另请参阅 terminate().
[静态]
void QThread::sleep(unsigned long secs)
强制当前线程休眠secs秒。
这是一个重载函数,等同于调用
QThread::sleep(std::chrono::seconds{secs});
[静态,自6.6以来]
void QThread::sleep(std::chrono::nanoseconds nsecs)
强制当前线程休眠nsecs。
如果您需要等待某个条件改变,请避免使用此函数。相反,可以将槽连接到指示改变的信号,或使用事件处理器(见QObject::event)。
注意:此函数不保证准确性。在负载较高的情况下,应用程序可能会睡眠时间超过nsecs。
此函数在Qt 6.6中引入。
uint QThread::stackSize() const
返回线程的最大堆栈大小(如果已通过setStackSize()设置);否则返回零。
另请参阅:setStackSize。
[槽]
void QThread::start(QThread::Priority priority = InheritPriority)
通过调用run()开始线程的执行。操作系统将根据priority参数来调度线程。如果线程已经正在运行,此函数将不起作用。
priority参数的效果取决于操作系统的调度策略。特别是,在不支持线程优先级的系统(例如Linux,有关更多详细信息,请参阅sched_setscheduler文档)上,priority将被忽略。
[私有信号]
void QThread::started()
当相关线程开始执行,在调用run()函数之前,会发出此信号。
注意: 这是一个私有信号。它可以在信号连接中使用,但不能由用户发出。
另请参阅:finished。
[槽]
void QThread::terminate()
终止线程的执行。根据操作系统的调度策略,线程可能立即终止,也可能不立即终止。在终止后使用QThread::wait()可以确保。
当线程终止时,所有等待线程完成的所有线程都将被唤醒。
警告:此函数很危险,不建议使用。线程可以在其代码路径的任何位置终止。线程可能在修改数据时终止。没有机会让线程自己清理,解锁任何持有的互斥锁等。简而言之,只有绝对必要时才使用此函数。
可以通过调用QThread::setTerminationEnabled()来显式启用或禁用终止。当禁用终止时调用此函数会导致终止被延迟,直到重新启用终止。有关更多信息,请参阅QThread::setTerminationEnabled()的文档。
注意: 此函数是 线程安全。
另请参阅:setTerminationEnabled。
[静态]
void QThread::usleep(unsigned long usecs)
这是一个重载函数,等同于调用
QThread::sleep(std::chrono::microseconds{secs});
注意:此函数不保证准确性。在负载较高的情况下,应用程序可能会睡眠时间超过usecs。某些操作系统可能会将usecs四舍五入到10 ms或15 ms;在Windows上,它将被四舍五入到1 ms的倍数。
bool QThread::wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever))
阻塞线程,直到满足以下任一条件
- 与该QThread对象关联的线程已完成执行(即在 run() 返回时)。如果线程已完成,则此函数将返回 true。如果线程尚未启动,它也会返回 true。
- deadline 已达到。如果达到截止日期,则此函数将返回 false。
设置为 QDeadlineTimer::Forever
(默认值)的截止日期计时器永远不会超时:在这种情况下,函数只有在线程从 run() 返回或线程尚未启动时才返回。
这提供了类似于 POSIX pthread_join()
函数的功能。
bool QThread::wait(unsigned long time)
这是一个重载函数。
time 是等待的时间(以毫秒为单位)。如果 time 为 ULONG_MAX,则等待将不会超时。
[static]
void QThread::yieldCurrentThread()
如果存在其他可运行的线程,则将当前线程的执行权交给另一个线程。请注意,操作系统决定切换到哪个线程。
© 2024 The Qt Company Ltd. 本文档的贡献者是各自所有者的版权。本提供的文档是根据自由软件基金会发布的 GNU 自由文档许可证第 1.3 版 的条款授权的。Qt 和相关的标志是 The Qt Company Ltd. 在芬兰和其他国家/地区的商标。所有其他商标均为其各自所有者的财产。