QT之线程
来源:互联网 发布:linux鼠标切出来 编辑:程序博客网 时间:2024/06/01 07:42
一、QT中线程使用原则
在实际的开发中线程的使用频率很高,尤其是在开发界面程序的时候。QT的UI线程负责界面的事件相应,而一些复杂的逻辑运算可以放在一个子线程中进行。QT中线程的使用有一个原则,对于界面的操作只能在UI主线程中操作,子线程不能对UI界面进行操作。如果在子线程中需要对界面进行操作,可以使用信号通知UI主线程,由UI主线程进行操作。
二、QT中的线程
在QT中启动线程有三种方法:QThread、QtConcurrent::run、QRunnable
1、QThread
QThread是最为常用的启动线程的方法,QThread提供了一种独立管理线程的方法。QThread启动的线程从虚函数run()开始执行,所以通常在使用QThread启动线程时我们需要实现一个QThread的派生类,重写虚函数run(),在run()函数中现实子线程的代码。如果我们只需要把一个对象放在子线程中执行,没有复杂的操作代码,我们也可以使用Qobject::moveToThread函数,把对象移动到子线程中。
QThread对线程的管理
(1)线程启动
我们可以通过start()函数启动线程,start()函数有一个参数Priority线程的优先级,可参考enum QThread::Priority的取值,当线程已经被启动则调用此函数无任何作用。当调用此函数之后,会自动调用函数函数run(),所以run()函数是线程的线程函数
(2)线程停止
我们可以通过调用exit()或quit()函数停止线程。调用之后QEventLoop::exec()结束消息循环并返回,exec()返回exit()指定的返回码。通常为了方便,返回0为成功,负数为失败。quit()等同exit(0)。
也可以调用terminate()函数强制终止线程,需要调用setTerminationEnabled()设置线程为可被终止,但是也不一定会立即终止线程,这个要以来操作系统的调度策略。在terminate()之后使用wait()函数等待,确保线程结束。使用terminate()终止线程一个危险的操作,在程序的任何地方都可以调用此函数终止线程,可能这时线程在修改数据。终止时线程也未释放线程占用的资源(内存、线程锁....),所以之后在不是必须使用的时候,不建议使用
实例一 实现QThread的派生类:
class WorkerThread : public QThread{ Q_OBJECT void run() { 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();}实例二 特定对象在线程执行,使用moveToThread
class Worker : public QObject{ Q_OBJECTpublic slots: void doWork(const QString ¶meter) { 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 &);};
注意:
每一个线程都有一个事件循环,使用QThread创建的线程同样也有一个事件循环。事件循环是信号和槽机制的重要组成部分,如果没有启动事件循环则信号与槽将不起作用。启动事件循环需要执行exec()函数,exec()函数是一个阻塞函数,而当我们派生QThread类重写run()函数时可能不想去执行exec(),因为这样最阻塞。这样就带来了一个问题,在线程中就不能使用信号与槽。如果我们需要在线程中使用信号与槽就必须执行exec()进行事件循环,这种情况可以采用实例二的方法,在封装一个线程操作对象,不进行重写run()函数而是对象在主线程中创建使用moveToThread()移动到子线程,这样在线程中就可以使用信号与槽,因为QThread::run()函数默认调用了exec()函数启动了事件循环
2、QtConcurrent::run
QtConcurrent命名空间里提供了一些高级API,利用这些API可以编写多线程程序,而不用直接使用比较低级的一些类,如mutext,lock, waitcondition以及semaphore等。使用QtConcurrent命令空间的API编写的程序会根据处理器的数目自动地调整线程的个数。QtConcurrent包含了用于并行列表处理的函数式编程,包含实现共享内存系统的MapReduce和FilterReduce, 以及管理GUI应用程序中异步计算的类。我们可以使用提供的run()函数,很方便的启动一个线程
using namespace QtConcurrent; void hello(QString name) { qDebug() << "Hello" << name << "from" << QThread::currentThread(); } int main(int argc, char **argv) { QApplication app(argc, argv); QFuture<void> f1 = run(hello, QString("Alice")); QFuture<void> f2 = run(hello, QString("Bob")); f1.waitForFinished(); f2.waitForFinished(); return app.exec(); }注意:同样存在在线程函数中不能使用信号与槽问题
3、QRunnable
作为Qt类中少有的基类, QRunnable提供了简洁有效的可运行对象的创建. 用QRunnable来创建独立的运行对象来运行 不涉及界面元素的数据处理过程 非常合适.
缺点: 无法实时提供自身的运行状态,没有start函数,需要QThreadPool启动线程
默认情况,QThreadPool最在线程结束时自动删除QRunnable对象,我们也可以通过QRunnable::setAutoDelete()方法可以改变该默认行为。QThreadPool支持在QRunnable::run方法中通过调用tryStart(this)来多次执行相同的QRunnable。当最后一个线程退出run函数后,如果autoDelete启用的话,将删除QRunnable对象。在autoDelete启用的情况下,调用start()方法多次执行同一QRunnable会产生竞态,就避免这样做。那些在一定时间内会使用的线程将会过期。默认的过期时间是30秒。可通过setExpiryTimeout()方法来设置。设置一个负数的超时值代表禁用超时机制。方法maxThreadCount()可以查询可使用的最大线程数,你也可以设置最大的线程数。activeThreadCount反应的是当前正在被使用中的线程数个数。reserveThread函数保留某个线程为外部用,releaseThread释放该线程,这样就可以被再次使用。
class HelloWorldTask : public QRunnable{ void run() { qDebug() << "Hello world from thread" << QThread::currentThread(); }}HelloWorldTask *hello = new HelloWorldTask();// QThreadPool takes ownership and deletes 'hello' automaticallyQThreadPool::globalInstance()->start(hello);
4、QThreadPool
QThreadPool管理一组线程。它负责管理和回收单个QThread对象以减少程序中线程创建的开销。每个Qt应用程序都有一个全局的QThreadPool对象,可通过方法globalInstance()获得。通常和QRunnable结合使用启动线程。在程序退出时也可以调用waitForDone()函数等待所有的线程退出
- Qt之线程同步
- QT之线程
- Qt之线程基础
- Qt之线程同步
- Qt之线程QThread
- Qt之线程同步
- QT总结之线程
- Qt线程之moveToThread
- Qt随笔之Qt线程同步
- Qt之线程和QObject
- qt 之线程调试篇
- Qt之线程(QThread)
- Qt之线程(QThread)
- qt线程同步之信号量
- QT线程例程之理解
- qt之进程和线程
- Qt之线程(QThread)
- Qt 线程同步之 QWaitCondition
- 此证书是由未知颁发机构签名的解决办法
- 安卓的工程文件介绍
- VC使用API和发送键盘消息模拟键盘(组合键)消息
- cocos2d-x lua c++ 相互调用代码中直接调用注册
- 坐标旋转(算法)
- QT之线程
- jackson 自定义解析类,处理复杂类型
- 【重构 改善既有代码的设计】之代码的坏味道
- 解决Android中xml文件Graphical Layout显示和真机运行显示不相同问题
- CocoaLumberjack开发指南
- html设定按钮位置示例
- reRender属性的使用
- HTTP1.1协议的chunked编码(chunked transfer encoding分块传输编码)
- android——Fragment与Activity