是否可以将对象实例移动到QT项目中不同代码点的不同线程?

时间:2016-06-27 15:50:51

标签: c++ multithreading qt

我正在尝试确定在运行时是否可以将一个对象实例移动到不同点的不同线程。

下面是一些示例代码,向您展示我的意思:

this->thread1           = new QThread( this );
this->thread2           = new QThread( this );

this->pObject->moveToThread( this->thread1 );

connect(this->thread1, SIGNAL(started()), this->pObject, SLOT(fnc1()));
connect(this->thread2, SIGNAL(started()), this->pObject, SLOT(fnc2()));

this->thread1->start();

//after thread1 has finished

this->pObject->moveToThread( this->thread2 );
this->thread2->start();

是否可以这样做?

编辑:在Kuba关于不使用直接连接的建议后,他指出我必须以某种方式干扰事件循环,我意识到手动终止线程并不是一个好主意。我在这里添加我的线程终止,以显示我出错的地方,并尝试找到更好的方法来实现相同的结果。

connect(this->pObject, SIGNAL(finished()), this, SLOT(stopThread()));

void Class::stopThread( void )
{
    if( this->thread1->isRunning() )
    {
        this->thread1->terminate();
        return;
    }

    if( this->thread2->isRunning() )
    {
        this->thread2->terminate();
        this->pObject->moveToThread( this->thread1 );
    }
}

void Object::fnc1( void )
{
    /*Does some work..*/

    finished(); //Calls 'finished' to signal stopThread when done (not stopping on its own)
}

附加信息 我有MainClass,它将实例保存到thread1,thread2和pObject(指向我试图从thread1移动到thread2的对象的指针,如果需要,再返回)。

主类构造函数:

MainClass::MainClass( QWidget *parent ) : QMainWindow(parent)
{
    this->ui.setupUi(this);

    this->thread1           = new QThread( this );
    this->thread2           = new QThread( this );

    this->pObject->moveToThread( this->thread1 );

    connect( this->pObject, SIGNAL(finished()), this, SLOT(stopThread()) );
    connect( this->thread1, SIGNAL(started()), this->pObject, SLOT(fnc1()) );
    connect( this->thread2, SIGNAL(started()), this->pObject, SLOT(fnc2()) );   
}

单击菜单项时的插槽:

void MainClass::on_action_call_fnc1_triggered( void )
{
    if( this->thread1->isRunning() )
        return;

    /*EXECUTES SOME CLASSIFIED CODE THAT CANNOT BE SHOWN*/

    this->thread1->start();//should trigger fnc1 execution
}

fnc1保存在Thread1启动时调用的Object类中:

void Object::fnc1( void )
{
    /*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
    this->finished(); // triggers MainClass::stopThread( void )
}

单击菜单项以启动fnc2执行时的插槽:

void MainClass::on_action_call_fnc2_triggered( void )
{
    if( this->thread1->isRunning() || this->thread2->isRunning() )
        return;

    this->pObject->moveToThread( this->thread2 );
    this->thread2->start();//should trigger fnc2 execution
}

fnc2在对象中保存:

void Object::fnc2( void )
{
   /*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
    this->finished(); // triggers MainClass::stopThread( void )
}

stopThread功能:

void MainClass::stopThread( void )
{
    if( this->thread1->isRunning() )
    {
        /*this->thread1->quit();
        this->thread1->exit();*/
        this->thread1->terminate();
        //this->thread1->wait( 0 ); //Trying different ways of stopping the thread
        return;
    }

    if( this->thread2->isRunning() )
    {
        this->thread2->terminate();
        //this->thread2->quit(); // Trying different ways of stopping the thread
        //this->thread2->exit();
        this->pObject->moveToThread( this->thread1 );
    }
}

1 个答案:

答案 0 :(得分:2)

它会工作,但你必须断言对象的线程确实已完成:

Q_ASSERT(pObject->thread() == nullptr);
pObject->moveToThread(thread2);

thread1完成时,对象的线程变为null,然后才允许您将其从任意线程移动到另一个线程。否则,如果对象的线程尚未完成,则只能从其线程中移动对象:

QTimer::singleShot(0, pObject, [this]{ pObject->moveToThread(thread2); }