moveToThread后成员函数到底在哪里运行

之前一直使用继承QThread的方法使用QT的多线程功能。这种方式下,只有run()函数内的程序段是真正运行于子线程中的。

为了搞明白moveToThread这种更“正确”方法的特点,专门做了一次实验

先贴代码。首先定义了一个测试用的类。类里面有一个槽函数,并且通过槽函数调用了一个私有方法

头文件中:
#ifndef THREAD_TEST_H
#define THREAD_TEST_H

#include <QObject>

#include "globle_define.h"

class thread_test : public QObject
{
    Q_OBJECT
private:
    void work_call(QString user);
public:
    explicit thread_test(QObject *parent = nullptr);
    ~thread_test();

signals:

public slots:
    void work(QString user);



};

#endif // THREAD_TEST_H


源文件中:
#include "thread_test.h"

#include <QThread>



thread_test::thread_test(QObject *parent) : QObject(parent)
{
     qDebug()<<"setup ID:"<<QThread::currentThreadId();
}

thread_test::~thread_test()
{
    qDebug()<<"kill ID:"<<QThread::currentThreadId();
}

void thread_test::work(QString user)
{
    qDebug()<<user<<"work slot ID:"<<QThread::currentThreadId();
    work_call(user);
}


void thread_test::work_call(QString user)
{
    qDebug()<<user<<"work call ID:"<<QThread::currentThreadId();
}

接下来是测试方法:


   qDebug()<<"主函数ID:"<<QThread::currentThreadId();
   qDebug()<<"*********直接调用测试*********";
   thread_test one(this);
   one.work(tr("直接调用"));       //这里测试是在主线程

   qDebug()<<"*********先调用测试*********";
   QThread thread_1(this);
   thread_test two;
   connect(this, SIGNAL(test(QString)), &two, SLOT(work(QString)));
   emit test(tr("移入之前信号调用"));       //这里测试是在主线程
   two.moveToThread(&thread_1);
   emit test(tr("移入之后信号调用"));    //这里测试是在子线程
   thread_1.start();
   emit test(tr("start之后信号调用"));   //这里测试是在子线程
   Sleep(200);
   disconnect(this, SIGNAL(test(QString)), &two, SLOT(work(QString)));

    qDebug()<<"*********先Move测试*********";
   QThread thread_2(this);
   thread_test three;
   three.moveToThread(&thread_2);
   three.work(tr("移入之后直接调用"));   //这里测试是在主线程
   connect(this, SIGNAL(test(QString)), &three, SLOT(work(QString)));
   emit test(tr("移入之后信号调用"));  //这里测试是在子线程
   thread_2.start();
   emit test(tr("start之后信号调用"));  //这里测试是在子线程

    qDebug()<<"测试结束";
    Sleep(5000);

最后是测试结果:

主函数ID: 0x3904

*********直接调用测试*********

setup ID: 0x3904

"直接调用" work slot ID: 0x3904

"直接调用" work call ID: 0x3904

*********先调用测试*********

setup ID: 0x3904

"移入之前信号调用" work slot ID: 0x3904

"移入之前信号调用" work call ID: 0x3904

"移入之后信号调用" work slot ID: 0x46b8

"移入之后信号调用" work call ID: 0x46b8

"start之后信号调用" work slot ID: 0x46b8

"start之后信号调用" work call ID: 0x46b8

*********先Move测试*********

setup ID: 0x3904

"移入之后直接调用" work slot ID: 0x3904

"移入之后直接调用" work call ID: 0x3904

测试结束

"移入之后信号调用" work slot ID: 0x4a18

"移入之后信号调用" work call ID: 0x4a18

"start之后信号调用" work slot ID: 0x4a18

"start之后信号调用" work call ID: 0x4a18

kill ID: 0x3904

结论:

1. 在moveToThread之前,子类所有的方法在主进程内运行,无论是直接调用还是通过信号和槽调用

2. moveToThread之后,子类通过信号和槽系统调用的方法,都在子线程内运行;直接调用也是可以的,带来的所有工作都在主进程内发生

3. moveToThread之后,是否start对方法在哪个线程内调用没有影响

4. 构造和析构函数永远都在主线程内调用

5. 一个在实验里没有体现的结论:在子线程中调用一个静态函数,会在一个非子线程也非主线程的新线程中运行,运行完后就这个新线程就销毁了...这是什么神仙操作

猜你喜欢

转载自blog.csdn.net/laoponline/article/details/112457332