Reputation: 493
I am trying to determine if you can move one object instance to different threads at different points during run-time.
Below is some sample code to show you what I mean:
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();
Is it possible to do this?
Edit: After Kuba's advice on not using a direct connection and him pointing out I must be interfering with the event loop somehow, I realised manually terminating the threads was not a good idea. I am adding my termination of the threads here to show where I am going wrong and to try and find a better way of achieving the same result.
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)
}
ADDITIONAL INFO I have MainClass which holds the instances to both thread1, thread2 and pObject (pointer to the object I am trying to move from thread1 to thread2 and back again if necessary).
Main class constructor:
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()) );
}
Slot for when menu item is clicked:
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 held in Object class that is called when thread1 starts:
void Object::fnc1( void )
{
/*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
this->finished(); // triggers MainClass::stopThread( void )
}
Slot for when menu item is clicked to start fnc2 executing:
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 held in Object:
void Object::fnc2( void )
{
/*DOES SOME MORE SECRET PROCESSING THAT CANNOT BE SHOWN*/
this->finished(); // triggers MainClass::stopThread( void )
}
stopThread function:
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 );
}
}
Upvotes: 2
Views: 828
Reputation: 98425
It will work, but you have to assert that the object's thread is indeed finished:
Q_ASSERT(pObject->thread() == nullptr);
pObject->moveToThread(thread2);
When thread1
is finished, the object's thread becomes null and only then you're allowed to move it to another thread from arbitrary thread. Otherwise, if object's thread is not finished yet, you could only move the object from its thread:
QTimer::singleShot(0, pObject, [this]{ pObject->moveToThread(thread2); }
Upvotes: 2