- 方案1
Qt中创建独立的线程,一般都是采用继承QThread类,然后重写run虚函数,在run函数中执行任务。
class CThread: public QThread
{
Q_OBJECT
public:
CThread(QObject *parent = nullptr){}
private:
virtual void run()
{
//task
while(true)
{
}
}
}
当需要在独立的线程中用到自定义的类,用到信号槽的时候,需要在独立线程中,开启一个新的事件循环,此时我们可以这样用,定义好类,然后执行exec,如果需要退出,则调用QThread::quit()函数,安全退出。
class CThread: public QThread
{
Q_OBJECT
public:
CThread(QObject *parent = nullptr){}
private:
virtual void run()
{
//task
clas CMyClass my;
exec();
}
}
第二种方案, 是平时用的比较多的。但是也有缺点,就是要写的类比较多,CThread类,CTask类,然后CTask类需要与主程序交互的时候,需要信号槽的跳转,这样就有点麻烦。然后研究了一下moveToThread发现这个方法还是比较方便,就是使用的时候需要注意,否则很容易将主线程与子线程混淆,下面将一般用法进行总结。
//伪代码
class CThread: public QThread
{
Q_OBJECT
public:
CThread(QObject *parent = nullptr)
{
//主线程
m_thread = new QThread(this);
connect(m_thread, SIGNAL(started()), this, SLOT(OnThreadStarted()));
connect(m_thread, SIGNAL(finished()), this, SLOT(OnThreadFinished()));
moveToThread(m_thread);
m_thread->start();
}
private:
//不需要使用到信号槽的,不继承QObject类的成员变量,可以在主线程中创建
int m_id;
QString m_name;
QThread *m_thread;
//继承QObject的类,要在子线程中创建
QTimer *m_timer;
signals:
void mySignal();
private slots:
void OnThreadStarted()
{
//子线程,一定要在子线程中创建,这样后续的信号与槽都是在子线程中执行
timer = new QTimer; //不能加this
connect(timer, SIGNAL(timeout()), this, SLOT(OnTimeout()));
timer->start(1000);
}
void OnThreadFinished()
{
//子线程 线程退出,释放资源
timer->deleteLater();
}
void OnTimeout()
{
//子线程
}
}
上送方法相比第二种方案,可以在一个类中,实现独立的线程执行,并且用到事件循环。代码可以简洁一些。
通过上面的分析可以发现,Qt线程的关键点就是,QOjbect子类,在哪个线程中创建,它就在哪个线程中进行事件循环。例如方法三中QTimer类,不能在主线程中创建。