QThread类提供一种独立于平台的线程管理方式。
头文件 | #include <QThread> |
---|---|
qmake | QT += core |
继承于 | QObject |
1.公有类型
enum | Priority { IdlePriority, LowestPriority, LowPriority, NormalPriority, …, InheritPriority} |
---|---|
2.公有函数
QThread(QObject *parent = nullptr) | |
---|---|
virtual | ~QThread() |
QAbstractEventDispatcher * | eventDispatcher() const |
void | exit(int returnCode = 0) |
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(unsigned long time = ULONG_MAX) |
3.公有重载函数
virtual bool | event(QEvent *event) override |
---|---|
4.公有槽函数
void | quit() |
---|---|
void | start(QThread::Priority priority = InheritPriority) |
void | terminate() |
5.信号
void | finished() |
---|---|
void | started() |
6.静态公有成员
QThread * | create(Function &&f, Args &&… args) |
---|---|
QThread * | create(Function &&f) |
QThread * | currentThread() |
Qt::HANDLE | currentThreadId() |
int | idealThreadCount() |
void | msleep(unsigned long msecs) |
void | sleep(unsigned long secs) |
const | QMetaObject staticMetaObject |
void | usleep(unsigned long usecs) |
void | yieldCurrentThread() |
7.受保护函数
int | exec() |
---|---|
virtual void | run() |
8.静态受保护成员
void | setTerminationEnabled(bool enabled = true) |
---|---|
9.详细描述
QThread类提供一种独立于平台的线程管理方式。
一个QThread实例管理程序中的一个线程。QThread的执行开始于run()。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。
9.1使用QThread方法
方法1(工作对象方法)
你可以使用QObject::moveToThread()将工作对象移动到线程中使用。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39class 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 &);
};
将线程移动到工作线程内执行。因为在线程中有队列的信号槽连接机制,所以在不同线程中使用信号槽是安全的。
方法2(继承QThread方法)
另一种单独在线程中执行的方式是继承QThread后重新实现run()函数(run函数内用户的执行操作)。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class 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()在新线程中执行。如果从两个函数访问一个成员变量,则从两个不同的线程访问该变量。需要检查这样做是否安全。
注意:在跨不同线程与对象交互时必须小心。有关详细信息,请参见同步线程。
9.2管理线程
QThread会通过信号started()
和finished
通知你,或者您可以使用isFinished()
和isRunning()
查询线程的状态。
你可以调用exit()
和quit()
来停止线程。在极端的情况下,你希望强制使用terminate()
来终止线程。但是,这样做是又危险又令人气馁。详细请读terminate()
和setTerminateEnabled()
相关文档。
从Qt4.8起,通过将finished()
信号连接到QObject::deleteLater()
,可以释放位于刚刚结束的线程中的对象。
使用wait()
来阻塞调用线程,直到另外一个线程执行完成或直到经过指定时间。
QThread还提供了与平台无关的静态睡眠函数:sleep()
、msleep()
和usleep()
分别为秒、毫秒和微秒。这些函数在Qt 5.0中是公有函数(Qt 4.0版本为保护函数)。
注意:wait()和sleep()函数通常是不必要的,因为Qt是一个事件驱动框架。与其使用wait(),还不如考虑监听finished()信号,或使用QTimer代替sleep()函数。
静态函数currentThreadID()
和currentThread()
返回当前执行线程的标识符。前者返回线程的平台特定ID;后者返回QThread指针。
要选择线程的名称(例如,在Linux上的命令ps -L标识),可以在启动线程之前调用setObjectName()
。如果不调用setObjectName(),则给线程的名称将是线程对象运行时类型的类名(例如,对于Mandelbrot示例中的”RenderThread”,因为它是QThread子类的名称)。请注意,目前在Windows的发布版本中不可用。
另外请参阅,Qt在线程中的支持, QThreadStorage, 同步线程, Mandelbrot示例, 信号量示例, 等待条件示例.
10.成员类型文档
枚举 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 | 使用与创建线程相同的优先级。(这是默认值) |
11.成员函数文档
1 | QThread::QThread(QObject *parent = nullptr) |
构造一个新QThread来管理一个新线程。父线程拥有QThread的所有权。直到调用start(),线程才开始执行。
另外请参阅start()
。
1 | [virtual] QThread::~QThread() |
销毁QThread。
注意,删除QThread对象不会停止它管理的线程的执行。删除正在运行的QThread(即isFinished()返回false)将导致程序崩溃。在删除QThread之前,等待finished()信号。
1 | [static] QThread *QThread::create(Function &&f, Args &&... args) |
创建一个新的QThread对象,该对象将使用参数args和执行函数f。
新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
返回新创建的QThread实例。
注意:调用者获得返回的QThread实例的所有权。
注意:此函数仅在使用c++ 17时可用。
警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。
该函数从Qt 5.10中引入。
另外请参阅start()
。
1 | static] QThread *QThread::create(Function &&f) |
创建一个新的QThread对象,该对象将执行函数f。
新线程没有启动,它必须通过显式调用start()启动。这允许您连接到它的信号,将QObjects移动到线程,选择新线程的优先级等等。函数f将在新线程中调用。
返回新创建的QThread实例。
注意:调用者获得返回的QThread实例的所有权。
注意:此函数仅在使用c++ 17时可用。
警告:不要多次调用返回的QThread实例上的start(),这样做会导致未定义的行为。
该函数从Qt 5.10中引入。
另外请参阅start()
。
1 | [static] QThread *QThread::currentThread() |
返回一个指向管理当前执行线程的QThread的指针。
1 | [static] Qt::HANDLE QThread::currentThreadId() |
返回当前执行线程的线程句柄。
注意:在Windows上,这个函数返回由Win32函数GetCurrentThreadId()返回的DWORD(Windows线程ID),而不是由Win32函数GetCurrentThread()返回的伪句柄(Windows线程句柄)。
警告:此函数返回的句柄用于内部目的,不应在任何应用程序代码中使用。
1 | [override virtual] bool QThread::event(QEvent *event) |
重新实现QObject::event()
。
1 | QAbstractEventDispatcher *QThread::eventDispatcher() const |
返回指向线程的事件调度程序对象的指针。如果线程不存在事件调度程序,则此函数返回0。
该函数从Qt 5.0中引入。
另外请参阅setEventDispatcher()
。
1 | [protected] int QThread::exec() |
进入事件循环,并等待直到调用exit(),返回传递给exit()的值。如果通过quit()调用exit(),返回的值为0。
这个函数应该在run()中调用。需要调用这个函数(run()
)来启动事件处理。
另外请参阅quit()
和exit()
。
1 | void QThread::exit(int returnCode = 0) |
告诉线程的事件循环使用退出代码
退出。
调用此函数后,线程离开事件循环,并从对QEventLoop::exec()
的调用返回。QEventLoop::exec()
函数返回退出代码
。
按照惯例,退出代码为0表示成功,任何非零值表示错误。
请注意,与同名的C库函数不同,此函数会返回到调用者和停止的事件处理。
调用exit
函数后在此线程中不再启动QEventLoop
,直到再次调用QThread::exec()
。 如果QThread::exec()
中的事件循环没有运行,那么下一次调用QThread::exec()
也会立即返回。
另外请参阅quit
与QEventLoop
。
1 | [signal] void QThread::finished() |
该信号在完成执行之前从关联线程中发出。
发出此信号时,事件循环已停止运行。 除延迟删除事件外,线程中不再处理任何事件。 此信号可以连接到QObject::deleteLater()
,以释放该线程中的对象。
注意:如果使用terminate()
终止关联的线程,则不确定从哪个线程发出此信号。
注意:这是一个私有信号。它可以用于信号连接,但不能由用户发出。
另外请参阅started()
。
1 | [static] int QThread::idealThreadCount() |
返回可在系统上运行的理想线程数。这样就可以查询系统中的实际和逻辑处理器内核的数量。如果无法检测到处理器核心数,则此函数返回1。
1 | bool QThread::isFinished() const |
如果线程结束则返回true
,否则返回false
。
另外请参阅isRunning
。
1 | bool QThread::isInterruptionRequested() const |
如果可以停止在此线程上运行的任务,则返回true。requestInterruption()
函数可以进行请求中断操作。
此函数可用于长时间运行的任务中判断中断状态。 从不检查或操作此函数的返回值是安全的,但建议在长时间运行的函数中定期执行此操作。
注意:不要经常调用它,以保持低开销。
1 | void long_task() { |
译者注:
1
2
3
4
5
6
7 >virtual void run() Q_DECL_OVERRIDE {
> while (!isInterruptionRequested()) // 判断是否请求终止
> {
> /* 用户耗时操作 */
> }
>}
>
该函数从Qt 5.2中引入。
另外请参阅currentThread()
和requestInterruption()
。
1 | bool QThread::isRunning() const |
如果线程正在运行则返回true
,否则返回false
。
另外请参阅isFinished()
。
1 | int QThread::loopLevel() const |
返回线程的当前事件循环级别。
注意:这只能在线程本身内调用,即当它是当前线程时。
该函数从Qt 5.5引入。
1 | [static] void QThread::msleep(unsigned long msecs) |
强制当前线程休眠msecs
毫秒。
如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event()
)。
注意:此功能不保证准确性。 在重负载条件下,应用程序可能比msecs
睡眠时间更长。 某些操作系统可能会将msecs
舍入到10 ms或15 ms。
另外请参阅sleep()
和usleep
。
1 | QThread::Priority QThread::priority() const |
返回正在运行的线程的优先级。 如果线程未运行,则此函数返回InheritPriority
。
该函数从Qt 4.1中引入。
另外请参阅Priority
,setPriority()
和start()
。
1 | [slot] void QThread::quit() |
告诉线程的事件循环退出并返回代码0(成功)。相当于调用QThread::exit(0)
。
如果线程没有事件循环,则此函数不执行任何操作。
另外请参阅exit()
和QEventLoop
。
1 | void QThread::requestInterruption() |
请求中断线程。 该请求是建议性的,由线程上运行的代码来决定它是否以及如何根据此类请求执行操作。此函数不会停止在线程上运行的任何事件循环,也不会以任何方式终止它。
译者注:
示例:
- 当用户执行
killAndWait()
函数后则会导致run()
函数内循环体结束,从而结束线程执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 >class WorkerThread : public QThread
>{
> Q_OBJECT
>public:
> void killAndWait()
> {
> requestInterruption(); /* 请求终止 */
> quit();
> wait();
> }
>
>protected:
> virtual void run() Q_DECL_OVERRIDE
> {
> while (!isInterruptionRequested()) /* 判断是否终止 */
> {
> /* 用户耗时操作 */
> }
> }
>};
>
该函数从Qt 5.2中引入。
另外请参阅isInterruptionRequested()
。
1 | [virtual protected] void QThread::run() |
线程的起点。在调用start()
之后,新创建的线程自动调用此函数。默认实现只是调用exec()
。
您可以重新实现此功能以便于高级线程管理。 从此方法返回将结束线程的执行。
另外请参阅start()
和wait()
。
1 | void QThread::setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) |
将线程的事件调度器设置为eventDispatcher
。 只有当没有为该线程安装事件调度器时,才可以执行此操作。 也就是说,在使用start()
启动线程之前,或者在主线程的情况下,在实例化QCoreApplication
之前。 此方法获取对象的所有权。
该函数从Qt 5.0中引入。
另外请参阅eventDispatcher()
。
1 | void QThread::setPriority(QThread::Priority priority) |
此函数设置正在运行的线程的优先级。 如果线程没有运行,则此函数不执行任何操作并立即返回。使用start()
启动具有特定优先级的线程。
优先级参数可以是QThread::Priority
枚举中的任何值,但InheritPriorty
除外。
优先级参数的影响取决于操作系统的调度策略。 特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅http://linux.die.net/man/2/sched_setscheduler以获取更多详细信息)。
该函数从Qt 4.1中引入。
另外请参阅Priority
,priority()
和start()
。
1 | void QThread::setStackSize(uint stackSize) |
将线程的最大堆栈大小设置为stackSize
。如果stackSize
大于0,则最大堆栈大小设置为stackSize
字节,否则最大堆栈大小由操作系统自动确定。
警告:大多数操作系统对线程堆栈大小设置了最小和最大限制。如果堆栈大小超出这些限制,则线程将无法启动。
另外请参阅stackSize()
;
1 | [static protected] void QThread::setTerminationEnabled(bool enabled = true) |
根据enabled
参数启用或禁用当前线程的终止。该线程必须由QThread启动。
如果enabled
为false
,则禁用终止。对QThread::terminate()
的未来调用将立即返回而不起作用。相反,终止延迟直到启用终止。
如果enabled
为true
,则启用终止。对QThread::terminate()
的未来调用将正常终止该线程。 如果终止已被延迟(即在终止禁用的情况下调用QThread::terminate()
),则此函数将立即终止调用线程。 请注意,在这种情况下,此函数不会返回。
另外请参阅terminate()
。
1 | [static] void QThread::sleep(unsigned long secs) |
强制当前线程休眠secs
秒。
如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event()
)。
注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。
另外请参阅msleep()
和usleep()
。
1 | uint QThread::stackSize() const |
返回线程的最大堆栈大小(如果使用setStackSize()
设置),否则返回0。
另外请参阅setStackSize()
。
1 | [slot] void QThread::start(QThread::Priority priority = InheritPriority) |
通过调用run()
开始执行该线程。操作系统将根据优先级参数调度线程。如果线程已在运行,则此函数不执行任何操作。
优先级参数的影响取决于操作系统的调度策略。特别是,在不支持线程优先级的系统上将忽略优先级(例如在Linux上,请参阅sched_setscheduler文档以获取更多详细信息)。
另外请参阅run()
和terminate()
。
1 | [signal] void QThread::started() |
在调用run()
函数之前,该信号在开始执行时从关联的线程发出。
注意:这是一个私有信号。 它可以用于信号连接,但不能由用户发出。
另外请参阅finished()
。
1 | [slot] void QThread::terminate() |
终止线程的执行。根据操作系统的调度策略,线程可能会立即终止也可能不会立即终止。 请确保terminate()
之后使用QThread :: wait()
来等待结束。
当线程终止时,所有等待线程都将被唤醒。
警告:此功能很危险,不鼓励使用。线程可以在其代码路径中的任何位置终止。修改数据时可以终止线程。会导致线程无法自行清理,解锁任何保持的互斥锁等。简而言之,只有在绝对必要的情况下才使用此功能。
可以通过调用QThread::setTerminationEnabled()
显式启用或禁用terminate()
的生效。在终止被禁用时调用此函数会导致终止延迟,直到重新启用终止。有关更多信息,请参阅QThread::setTerminationEnabled()
的文档。
另外请参阅setTerminationEnabled()
。
1 | [static] void QThread::usleep(unsigned long usecs) |
强制当前线程休眠usecs
秒。
如果您需要等待给定条件进行更改,请避免使用此功能。 相反,你应该将一个槽连接到指示更改的信号或使用事件处理程序(请参阅QObject::event()
)。
注意:此功能不保证准确性。 在重负载条件下,应用程序可能会睡眠时间更长。一些操作系统可能将usecs
调到10 ms或15 ms;另外在Windows上,它将调到1ms的倍数。
另外请参阅sleep()
和usleep()
。
1 | bool QThread::wait(unsigned long time = ULONG_MAX) |
阻塞线程,直到满足以下任一条件:
- 条件1:与此QThread对象关联的线程已完成执行(即从
run()
返回时)。如果线程已完成,此函数将返回true。 如果线程尚未启动,它也会返回true。 - 条件2:等待的时间已过。 如果时间是ULONG_MAX(默认值),那么等待将永远不会超时(线程必须从
run()
返回)。 如果等待超时,此函数将返回false。
这提供了与POSIX pthread_join()
函数类似的功能。
另外请参阅sleep()
和terminate()
。
1 | [static] void QThread::yieldCurrentThread() |
如果有的话,将当前线程的执行产生到另一个可运行的线程。请注意,操作系统决定切换到那个线程。
译者注: 放弃当前时间片切换到其他线程,而切换到那一个线程由系统决定。
原文来源:
1
https://doc.qt.io/qt-5/qthread.html
译者:Qt君