作者:Hykun | 来源:互联网 | 2023-09-04 18:34
QThread用法 为了创建新的线程执行相应处理,继承 QThread 并且重新实现 run() 实例化创建的线程子类,并调用 start() 想要设置线程优先级,通过设置 start()函数的priority 参数, 或者thread.setPriority(),默认继承所在线程的优先级。 QThread::IdlePriority QThread::LowestPriority QThread::LowPriority QThread::NormalPriority QThread::HighPriority QThread::HighestPriority QThread::TimeCriticalPriority QThread::InheritPriority
//MyThread.h class MyThread : public QThread { private:void run() override {// code to run in the new thread} };//main.cpp MyThread *thread = new MyThread; thread->start(); // starts a new thread which calls run() // ... thread->wait(); // waits for the thread to finish
从run()函数返回后,线程会终止运行 QThread::isRunning() 和 QThread::isFinished() 提供线程执行情况的信息 可以通过连接QThread::started() 和 QThread::finished() 信号获取相关状态 通过调用QThread::sleep() 函数临时停止线程的执行 通常情况下,事件驱动(或轮询)要好得多 通过调用wait()函数等待线程的结束。 在调用terminate()后,由于不同操作系统的策略不同,可以通过wait等待线程的结束。 wait(unsigned long time=ULONG_MAX) 通过参数设置等待的ms数 QThread 使用注意 在应用的非主线程中禁止:
执行任何GUI操作,例如: 使用任何QWidget / Qt Quick / QPixmap的API 使用 QImage, Qpainter等等 调用 Q(Core|Gui)Application::exec()事件循环 阻塞GUI线程 在销毁相应的QThread对象之前,要销毁相应线程中的qobject QThread 使用建议 在线程的run()里创建QObject 把QObject::deleteLater()槽函数连接到Qthread::finished()信号 将这个QObject移出到其他线程。 class MyThread : public QThread{ private:void run() override{MyQObject obj1, obj2, obj3;QScopedPointer p;if(condition)p.reset(new OtherQObject);auto anotherObj = new AnotherQObject;connect(this, &QThread::finished, anotherObj, &QObject::deleterLater);auto yetAnother = new YetAnotherQObject;// ...do stuff...//退出线程前,移动这个object到主线程yetAnother->moveToThread(qApp->thread());//以某种方式通知主线程关于这个object,所以可以在那里删除。//从这指针以后,不要从这个线程接触对象!} };
QThread 的使用 QThread的两种基本使用策略
Without an event loop(无事件循环) With an event loop(事件循环) 无事件循环(Event Loop)的QThread 继承QThread 的子类,并且重载 Qthread::run()函数。创建实例并且通过Qthread::start()启动线程。
class MyThread : public QThread{ private:void run() override{loadFilesFromDisk();doCalculations();saveResults();} };auto thread new MyThread; thread->start(); //some time later... thread->wait();
有事件循环(Event Loop)的QThrea 当使用timers, networking, queuedConnections等时,必须有事件循环。
Qt支持独立线程的事件循环
每个线程的内部事件循环为线程内部的Qobject提供事件。
在线程的run()函数里用QThread::exec() 开启事件循环:
class MyThread : public QThread{ private:void run() override{auto socket = new QTcpSocket;socket->connectToHost(...);exec();//run the event loop//cleanup} };
QThread::quit() 或 QThread::exit() 退出事件循环。
Qthread::run()默认实现就是调用Qthread::exec()进入事件循环。由于默认是进入Event loop,无需subclass Qthread ,允许我们更简便的使用,例如:
auto thread = new QThread; auto worker = new Worker;connect(thread, &QThread::started, worker, &Worker:doWork); connect(worker, &Worker:workDone, thread, &QThread:quit); connect(thread, &QThread:finished, worker,&Worker:deleteLater);worker->moveToThread(thread); thread->start();
线程间同步(Synchronization) 多线程需要注意什么?
对于共享资源的访问避免数据冲突
Qt提供跨平台的线程间同步的底层API
QMutex提供了互斥量和互斥操作 QSemaphore提供了一个整型信号灯(一种泛化的互斥) QWaitCondition is a condition variable QReadWriteLock提供了一个死锁允许同时进行读写操作 QAtomicInt提供对整型的自动操作 QAtomicPointer提供对指针的自动操作 来源于:
《Qt性能优化方案介绍》PPT