Qt多线程使⽤⽅法总结
Qt有两种开启多线程的⽅法,⼀种是继承QThread,然后重写run函数,另⼀种是把⼀个继承于QObject的类调⽤movetothread⽅法转移到⼀个Thread中。这两种⽅法都经常使⽤,这⾥记录⼀下需要注意的事项。
2015高考分数线⼀,继承QThread得到MyThread
MyThread只有run函数是运⾏在⼦线程中的,其它所有的函数运⾏在创建MyThread时的线程中。
新概念英语第一册课文
通俗来说就是如果你是在主线程中创建的MyThread,那么MyThread的其它函数就都运⾏在主线程中。所以,如果MyThread中有耗时的操作都要写在run函数中,否则会卡住主界⾯。因此如果MyThread中有某个变量既会被run函数使⽤,也会被其他函数使⽤,那么就要加锁,因为这涉及到跨线程的操作。
使⽤线程就会涉及到线程如何安全退出的问题。在这⾥什么时候线程会退出了?就是run函数运⾏结束的时候。如果你的run函数中没有死循环,那么当run函数运⾏结束,线程就⾃然退出了。如果有死循环了?显然调⽤线程的exit和quit是不起作⽤的,因为QThread并没有主动的调⽤exec()实现消息循环。那么最简单的⽅法就是添加⼀个bool变量,在主线程中通过修改这个bool变量的值来主动退出循环,结束run函数。
创建线程时也有⼀个问题需要注意,假设我们这么写 m_thread = new MyThread(this),这⾥的this指的是窗体的指针,意思就是创建线程时把窗体的指针作为⽗对象。那么我们不能⼿动delete m_thread。Qt会帮我们处理,但是我们要保证m_thread能够正常退出,也就是说在窗体的析构函数中先结束m_thread中的run函数(如果run中有死循环的话),然后调⽤m_thread->wait(),这些都要写在析构函数中delete ui前⾯。还有种创建线程的⽅式 m_thread = new MyThread,就是new线程时不指定⽗对象,那么通过绑定QThread::finished 信号和QObject::deleteLater槽也可以安全的退出线程(当然如果run函数中有死循环的话要先退出循环)。
⼆,继承QObject得到MyThread
MyThread的槽函数是运⾏在⼦线程中的,其它所有的函数运⾏在创建MyThread时的线程中。
⽤QObject来实现多线程有个⾮常好的优点,就是默认就⽀持事件循环。继承QThread要⽀持事件循环需要在QThread::run()中调
⽤QThread::exec()来提供对消息循环的⽀持,因此如果要使⽤信号和槽,那就直接使⽤QObject来实现多线程。QObject的线程转移函数是:void moveToThread(QThread * targetThread) ,通过此函数可以把⼀个顶层Object(就是没有⽗级)转移到⼀个新的线程⾥。
Qt的官⽅例⼦⼤概如下:
class Worker : public QObject
{
Q_OBJECT
........
........
//把需要在⼦线程中进⾏的操作都声明为槽函数
};
class Controller : public QObject
{
snatchQ_OBJECT
QThread workerThread;//普通的线程
public:
Controller()
{
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
//线程结束,⾃⼰退出
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
//这⾥去connect的线程的槽函数
//..............
//..............
workerThread.start();
yellowbook
}
~Controller()
{
workerThread.quit();
afootworkerThread.wait();
}
};
introduced
yyl使⽤QObject创建多线程的⽅法如下:
1. 写⼀个继承QObject的类,对需要进⾏复杂耗时逻辑的⼊⼝函数声明为槽函数
2. 此类在旧线程new出来,不能给它设置任何⽗对象
3. 同时声明⼀个QThread对象,在官⽅例⼦⾥,QThread并没有new出来,这样在析构时就需要调⽤QThread::wait(),如果是堆分配
boisterous
的话, 可以通过deleteLater来让线程⾃杀
4. 把obj通过moveToThread⽅法转移到新线程中,此时object已经是在线程中了
5. 把线程的finished信号和object的deleteLater槽连接,这个信号槽必须连接,否则会内存泄漏
6. 正常连接其他信号和槽(在连接信号槽之前调⽤moveToThread,不需要处理connect的第五个参数,否则就显⽰声明⽤
Qt::QueuedConnection来连接)
石家庄新东方官网>taurus
7. 初始化完后调⽤'QThread::start()'来启动线程
8. 在逻辑结束后,调⽤QThread::quit退出线程的事件循环