Qt 线程的详细介绍和使用
-
QT::QThread类提供了一种独立于平台的方式来管理线程。QThread对象管理程序中的一个控制线程。QThreads开始在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内部运行Qt事件循环
-
通过使用QObject::moveToThread()将worker对象移动到线程,可以使用它。线程将在运行函数返回后退出。除非调用exec(),否则线程中不会运行任何事件循环。
- 必须记住,QThread实例位于实例化它的旧线程中,而不是调用run()的新线程中。
- 这意味着QThread队列中的所有插槽都将在旧线程中执行。
- 因此,希望在新线程中调用插槽的开发人员必须使用worker-object方法;不应该将新插槽直接实现到子类QThread中。
- 在子类化QThread时,请记住,构造函数在旧线程中执行,而run()在新线程中执行。
- 如果从两个函数访问成员变量,则从两个不同的线程访问该变量。检查一下这样做是否安全。
- 当线程启动()和finished()时,QThread将通过一个信号通知您,或者您可以使用isFinished()和isRunning()来查询线程的状态。
- 您可以通过调用exit()或quit()来停止线程。在极端情况下,您可能希望强制终止一个正在执行的线程。然而,这样做是危险的,也是令人气馁的。详细信息请阅读terminate()和setTerminationEnabled()的文档。
- 从Qt 4.8开始,通过将finished()信号连接到QObject::deleteLater,就可以释放位于刚刚结束的线程中的对象
- 使用wait()来阻塞调用的线程,直到另一个线程完成执行(或者直到指定的时间过去)。
- QThread还提供静态的、平台无关的睡眠函数:sleep()、msleep()和usleep()分别允许完全秒级、毫秒级和微秒级的分辨率。这些功能在Qt 5.0中公开。
- 注意:一般来说,wait()和sleep()函数应该是不必要的,因为Qt是一个事件驱动框架。考虑侦听完成的()信号,而不是wait()。不要使用sleep()函数,考虑使用QTimer。
- 静态函数currentThreadId()和currentThread()返回当前执行线程的标识符。前者返回线程的平台特定ID;后者返回一个QThread指针。
- 要选择线程的名称(例如,通过Linux上的命令ps -L识别),可以在启动线程之前调用setObjectName()。如果您不调用setObjectName(),给线程的名称将是线程对象的运行时类型的类名(例如,在Mandelbrot示例中,“RenderThread”是QThread子类的名称)。请注意,目前在Windows上的版本中还不能使用这个功能。
一:Qthread成员函数介绍:
QThread(QObject *parent = Q_NULLPTR) | |
~QThread() | |
QAbstractEventDispatcher * | eventDispatcher() const 返回指向线程的事件调度程序对象的指针。如果线程不存在事件调度程序,则此函数返回0。 |
void | exit(int returnCode = 0) 告诉线程的事件循环使用返回代码退出。 |
bool | isFinished() const 该信号是在相关线程完成执行之前发出的。 |
bool | isInterruptionRequested() const 如果在此线程上运行的任务应该停止,则返回true。requestinterrupt()可以请求中断。 |
bool | isRunning() const 如果线程正在运行,返回true;否则返回false。 |
int | loopLevel() const 返回线程的当前事件循环级别。 |
Priority | priority() const 返回正在运行的线程的优先级。如果线程不运行,该函数返回InheritPriority。 |
void | 请求中断线程。该请求是建议性的,由线程上运行的代码决定是否以及如何响应该请求。此函数不会停止线程上运行的任何事件循环,也不会以任何方式终止它。 |
void | setEventDispatcher(QAbstractEventDispatcher *eventDispatcher) 将线程的事件调度程序设置为eventDispatcher。只有在还没有为线程安装事件分派器的情况下,才有可能做到这一点。也就是说,在使用start()启动线程之前,或者在主线程中,在实例化QCoreApplication之前。此方法拥有对象的所有权。 |
void | setPriority(Priority priority) 此函数设置正在运行的线程的优先级。如果线程没有运行,这个函数什么也不做,并且立即返回。使用start()启动具有特定优先级的线程。 |
void | setStackSize(uint stackSize) 将线程的最大堆栈大小设置为堆栈大小。如果堆栈大小大于零,则将最大堆栈大小设置为堆栈大小字节,否则操作系统将自动确定最大堆栈大小。 |
uint | stackSize() const 返回线程的最大堆栈大小(如果设置为setStackSize());否则返回0。 |
bool | wait(unsigned long time = ULONG_MAX) 阻塞线程,直到满足以下任一条件: 与此QThread对象关联的线程已经完成执行(即当它从run()返回时)。如果线程已经完成,这个函数将返回true。如果线程还没有启动,它还返回true。 |
二:run 方法
- QThreads开始在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内部运行Qt事件循环
QThread
{
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();
}
}
三:QObject::moveToThread() 方法
- 通过使用QObject::moveToThread()将worker对象移动到线程,可以使用它。因此,希望在新线程中调用插槽的开发人员必须使用worker-object方法;不应该将新插槽直接实现到子类QThread中。这种方法;
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 &);
};
总结:
具体的一些例子官方已经给出demo:
参见Qt、QThreadStorage、同步线程、Mandelbrot示例、信号量示例和等待条件示例中的线程支持一些实例:
Thread Support in Qt, QThreadStorage, Synchronizing Threads, Mandelbrot Example, Semaphores Example, and Wait Conditions Example.