2016-06-27 19 views
1

我正試圖確定您是否可以在運行時將一個對象實例移動到不同點上的不同線程。是否可以在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(); 

是否有可能做到這一點?

編輯:後庫巴的上不使用直接連接,他指出我必須在事件循環以某種方式干擾,我意識到手動終止線程是不是一個好主意的建議。我在這裏添加了我的線程終止,以顯示我出錯的地方,並嘗試找到獲得相同結果的更好方法。

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持有的情況下,這兩個線程1,線程2和pObject(指針我試圖從線程1移動如有必要,線程2,然後再返回的對象)。

主類的構造函數:

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())); 
} 

插槽被點擊菜單項時:在Object類舉行

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時調用線程1開始:

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); 
    } 
} 
+0

當你編譯並運行它會發生什麼? – user463035818

+0

這個問題沒有意義。內存在* all *線程之間共享,因此對象不能被「移動」到單個線程。 – o11c

+0

fnc1被調用並完成,然後我稱this-> thread2-> start();並且它不表示信號fnc2。 o11c,我相信QT已經以不同的方式實現了這個規範,這就是爲什麼我一開始就會持有你的反應,但是試圖學習QT我已經接受了這個是如何使用它的框架來完成的 – MikeO

回答

2

它將工作,但你必須斷言對象的線程確實完成:

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

thread1完成時,對象的線程變爲null,然後才允許你將它從任意線程移動到另一個線程。否則,如果對象的線程還沒有完成,你只能從它的線程移動對象:

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

你的答案加上在'connect'調用中加入'Qt :: DirectConnection'參數。謝謝。 – MikeO

+1

@MikeO你絕對不會*想要使用直接連接,因爲發送者和接收者在不同的線程中。具體而言,'fnc1'和'fnc2'將不會在'thread1'和'thread2'中被調用。你可以很容易地測試:在'fnc'開頭,斷言正確的線程:'void fnc1(){Q_ASSERT(thread()== QThread :: currentThread()); ''。這種斷言將通過設計與直接聯繫失敗。 **你正在做其他事情,例如阻塞thread1或2中的事件循環。** –

+1

我在函數調用完成後手動終止兩個線程,因爲它們看起來不是自己終止的,所以我想這就是爲什麼沒有直接連接,第二個線程將無法工作。我會更新我的主要帖子以顯示終止。我將刪除直接連接並找出更好的方法來結束該線程。 – MikeO

相關問題