简述

QThread类提供了与系统无关的线程。

QThread代表在程序中一个单独的线程控制。线程在run()中开始执行,默认情况下,run()通过调用exec()启动事件循环并在线程里运行一个Qt的事件循环。

详细描述

当线程started()和finished()时,QThread会通过一个信号通知你,可以使用isFinished()和isRunning()来查询线程的状态。

你可以通过调用exit()或quit()来停止线程。在极端情况下,可能要强行terminate()一个执行线程。但是,这样做很危险,下面会详细说明。

从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()槽。

使用wait()来阻塞调用的线程,直到其它线程执行完毕(或者直到指定的时间过去)。

QThread还提供了静态的、平台独立的休眠函数:sleep()、msleep()、usleep(),允许秒,毫秒和微秒来区分,这些函数在Qt5.0中被设为public。

注意:一般情况下,wait()和sleep()函数应该不需要,因为Qt是一个事件驱动型框架。考虑监听finished()信号来取代wait(),使用QTimer来取代sleep()。

静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回该线程平台特定的ID,后者返回一个线程指针。

要设置线程的名称,可以在启动线程之前调用setObjectName()。如果不调用setObjectName(),线程的名称将是线程对象的运行时类型(QThread子类的类名)。

线程管理

可以将常用的接口按照功能进行以下分类:

  • 线程启动

    • void start(Priority priority = InheritPriority) [slot]

      调用后会执行run()函数,但在run()函数执行前会发射信号started(),操作系统将根据优先级参数调度线程。如果线程已经在运行,那么这个函数什么也不做。优先级参数的效果取决于操作系统的调度策略。特别是那些不支持线程优先级的系统优先级将会被忽略(例如在Linux中,更多细节请参考http://linux.die.net/man/2/sched_setscheduler)。
  • 线程执行

    • int exec() [protected]

      进入事件循环并等待直到调用exit(),返回值是通过调用exit()来获得,如果调用成功则范围0。

    • void run() [virtual protected]

      线程的起点,在调用start()之后,新创建的线程就会调用这个函数,默认实现调用exec(),大多数需要重新实现这个函数,便于管理自己的线程。该方法返回时,该线程的执行将结束。

  • 线程退出

    • void quit() [slot]

      告诉线程事件循环退出,返回0表示成功,相当于调用了QThread::exit(0)。

    • void exit(int returnCode = 0)

      告诉线程事件循环退出。

      调用这个函数后,线程离开事件循环后返回,QEventLoop::exec()返回returnCode,按照惯例,0表示成功;任何非0值表示失败。

    • void terminate() [slot]

      终止线程,线程可能会立即被终止也可能不会,这取决于操作系统的调度策略,使用terminate()之后再使用QThread::wait(),以确保万无一失。当线程被终止后,所有等待中的线程将会被唤醒。

      警告:此函数比较危险,不鼓励使用。线程可以在代码执行的任何点被终止。线程可能在更新数据时被终止,从而没有机会来清理自己,解锁等等。。。总之,只有在绝对必要时使用此函数。

    • void requestInterruption()

      请求线程的中断。该请求是咨询意见并且取决于线程上运行的代码,来决定是否及如何执行这样的请求。此函数不停止线程上运行的任何事件循环,并且在任何情况下都不会终止它。

  • 线程等待

    • void msleep(unsigned long msecs) [static]

      强制当前线程睡眠msecs毫秒

    • void sleep(unsigned long secs) [static]

      强制当前线程睡眠secs秒

    • void usleep(unsigned long usecs) [static]

      强制当前线程睡眠usecs微秒

    • bool wait(unsigned long time = ULONG_MAX)

      线程将会被阻塞,等待time毫秒。和sleep不同的是,如果线程退出,wait会返回。

  • 线程状态

    • bool isFinished() const

      线程是否结束

    • bool isRunning() const

      线程是否正在运行

  • bool isInterruptionRequested() const

    如果线程上的任务运行应该停止,返回true。可以使用requestInterruption()请求中断。

    此函数可用于使长时间运行的任务干净地中断。从不检查或作用于该函数返回值是安全的,但是建议在长时间运行的函数中经常这样做。注意:不要过于频繁调用,以保持较低的开销。

void long_task() {
forever {
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
}
  • 线程优先级

    • void setPriority(Priority priority)

      设置正在运行线程的优先级。如果线程没有运行,此函数不执行任何操作并立即返回。使用的start()来启动一个线程具有特定的优先级。优先级参数可以是QThread::Priority枚举除InheritPriortyd的任何值。

枚举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 使用和创建线程同样的优先级. 这是默认值

使用方式

worker-object

可以使用worker-object通过QObject::moveToThread将它们移动到线程中。

class Worker : public QObject
{
Q_OBJECT public slots:
void doWork(const QString &parameter) {
QString result;
// 这里是昂贵的或阻塞的操作
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 &);
};

Worker槽中的代码将在一个单独的线程中执行,然而,可以自由地将Worker的槽函数连接到任何信号(来自任何对象、在任何线程中),在不同的线程里连接信号和槽也是安全的,这要归功于一个名为Qt::QueuedConnection的连接机制。

子类化QThread

另一种使代码运行在一个单独的线程中的方法,是子类化QThread中并重新实现的run()函数。

class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
// 这里是昂贵的或阻塞的操作
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();
}

上面的示例,在run()函数返回后线程就会退出,在线程中将不会有任何的事件循环运行,除非调用exec()。

重要的是要记住,一个线程实例位于实例化它的旧线程中,而非调用run()的新线程中,这意味着所有线程的queued slots将在旧线程中执行。因此,如果要在新线程调用槽函数必须使用worker-object方法,新的槽函数不应直接在子类化QThread中来实现。

当子类化QThread时,谨记构造函数在旧线程中执行,然而run()在新线程中执行。如果一个成员变量的访问来自两个函数,然后从两个不同的线程访问变量,需要检查这样做是否安全。

注意:用在不同的线程中的对象进行交互时必须小心。详见同步线程(Synchronizing Threads)。

耗时操作

  • requestInterruption()
  • isInterruptionRequested()

请参考:Qt之模型/视图(自定义进度条)

Qt之QThread的更多相关文章

  1. Qt之QThread(深入理解)

    简述 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程.对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题. 前面,已 ...

  2. 解析Qt中QThread使用方法

    本文讲述的是在Qt中QThread使用方法,QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用QThread,随便用goog ...

  3. Qt线程QThread简析(8个线程等级,在UI线程里可调用thread->wait()等待线程结束,exit()可直接退出线程,setStackSize设置线程堆栈,首次见到Qt::HANDLE,QThreadData和QThreadPrivate)

    QThread实例代表一个线程,我们可以重新实现QThread::run(),要新建一个线程,我们应该先继承QThread并重新实现run()函数. 需要注意的是: 1.必须在创建QThread对象之 ...

  4. Qt多线程-QThread

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QThread     本文地址:http://techieliang.com/2 ...

  5. Qt之QThread随记

    这是一篇随记,排版什么的就没有那么好了:) 首先要知道,一个线程在资源分配完之后是以某段代码为起点开始执行的,例如STL内的std::thread,POSIX下的pthread等,都是以函数加其参数之 ...

  6. Qt线程—QThread的使用--run和movetoThread的用法

    Qt使用线程主要有两种方法: 方法一:继承QThread,重写run()的方法 QThread是一个非常便利的跨平台的对平台原生线程的抽象.启动一个线程是很简单的.让我们看一个简短的代码:生成一个在线 ...

  7. QT下QThread学习(二)

    学习QThread主要是为了仿照VC下的FTP服务器写个QT版本.不多说,上图. FTP服务器的软件结构在上面的分析中就已经解释了,今天要解决的就是让每一个客户端的处理过程都可以按一个线程来单独跑.先 ...

  8. 【QT】 QThread部分源码浅析

    本文章挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...

  9. 【QT】QThread源码浅析

    本章会挑出QThread源码中部分重点代码来说明QThread启动到结束的过程是怎么调度的.其次因为到了Qt4.4版本,Qt的多线程就有所变化,所以本章会以Qt4.0.1和Qt5.6.2版本的源码来进 ...

随机推荐

  1. python hashlib、configparse、logging

    一.hashlib 1.Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等.     2.摘要算法 通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目 ...

  2. WPF中多线程统计拆箱装箱和泛型的运行效率

    WPF中多线程统计拆箱装箱和泛型的执行效率.使用的知识点有泛型.多线程.托付.从样例中能够看到使用泛型的效率至少提升2倍 MainWindow.xaml <Window x:Class=&quo ...

  3. WIN7使用VisualSVN建立SVN服务器

    使用SVN开发十分的方便,这样就不用每次都拷贝粘贴来备份了,网上看到一篇给自己的windows电脑安装SVN服务器的使用非常方便. 1.下载安装文件(服务器端和客户端) 服务器端采用VisualSVN ...

  4. HDU 4609 FFT+各种分类讨论

    思路: http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html 其实我是懒得写了.... 一定要define int long ...

  5. SpringMVC(三) RESTful架构和文件上传下载

    RESTful架构 REST全名为:Representational State Transfer.资源表现层状态转化.是目前最流行的一种互联网软件架构. 它结构清晰.符合标准.易于理解.扩展方便,所 ...

  6. (转载) Android开发mac /dev/kvm is not found

    Android开发mac /dev/kvm is not found 标签: KVMAndroid开发KVM is not found芒果Android芒果iOS 2016-10-29 16:31 2 ...

  7. Codeforces 987B. High School: Become Human

    解题思路: 1.题意:判断x^y和y^x谁大谁小. 2.由于x^y和y^x太大了,时间复杂度也不允许,所以做同等变换,比较e^(ylnx)和e^(xlny). 3.即为比较ylnx和xlny的大小. ...

  8. 手工清理win7系统C盘的技巧

    在我们日常使用电脑的过程中,随着使用的时候越久,大家就会发现电脑的运行速度变的越慢了,大家都知道很多系统东西一般都会安装在C盘,系统在运行的时候就会不断的产生垃圾文件以及其他我们根本用不到的文件,这样 ...

  9. MyEclipse 启动之 java.lang.RuntimeException: No application id has been

    found. 今天公司刚买来一台服务器,配置安装 java 开发环境的时候,MyEclipse 无法启动,查看日志文件之后,具体错误信息 如下: [java] view plaincopyprint? ...

  10. 【原创】ActiveMQ集群JDBC持久化

    在activemq.xml中配置持久化方式: <bean id="oracle-ds" class="org.apache.commons.dbcp.BasicDa ...