2016-07-27 20 views
1

故事:

我在我的應用程序中對每個「長」操作使用QtConcurrent API。 它工作得很好,但是我在創建QObject時遇到了一些問題。任何方式來檢測QObject是否屬於「死」QThread?

考慮這一段代碼,它使用一個線程來創建一個「富」的對象:

QFuture<Foo*> = QtConcurrent::run([=]() 
{ 
    Data* data = /*long operation to acquire the data*/ 
    Foo* result = new Foo(data); 
    return result; 
}); 

它運作良好,但如果「富」類從QObject的類派生的「結果」實例屬於創建該對象的QThread。

所以要使用正確的信號與「結果」實例/插槽,一個人應該做這樣的事情:現在

QFuture<Foo*> = QtConcurrent::run([=]() 
{ 
    Data* data = /*long operation to acquire the data*/ 
    Foo* result = new Foo(data); 
    // Move "result" to the main application thread 
    result->moveToThread(qApp->thread()); 
    return result; 
}); 

,所有作品exepected,我認爲這是正常的行爲和標稱解。

問題:

我有很多這樣的代碼,有時創建對象,也可以創建一個對象。它們中的大多數都是使用「moveToThread」調用正確創建的。

但有時候,我想念一個「moveToThread」調用。

然後,很多事情看起來像他們不工作(因爲這個對象插槽是「破」),沒有任何Qt警告。

現在,我有時會花很多時間來判斷爲什麼someting不起作用,因爲在理解它之前,只是因爲插槽沒有在特定的對象實例上被調用。

問題:

有什麼辦法幫我,以防止/檢測/調試這種情況? 例如:

  • 每次刪除QThread時都會記錄一條警告,但有屬於它的對象還活着嗎?
  • 每次信號發射到QThread被刪除的對象時都會記錄警告?
  • 每當信號發送到對象(在另一個線程中)並且在超時之前未處理時,都會記錄警告嗎?

感謝

+0

是否有一個原因是,'Foo'類型'的QObject必須具有非主線程關係(我認爲你的意思是「屬於」)? – eclarkso

+0

第三個問題是重複的;請刪除它。你在問如何檢測掛起的事件循環 - 這與是否有信號被髮射無關。請參閱[這裏](http://stackoverflow.com/q/25038829/1329652)。 –

回答

2

它可以跟蹤對象的線程之間運動。就在對象移動到新線程之前,它會發送一個ThreadChange事件。您可以過濾該事件並讓您的代碼運行以記錄對象何時離開線程。但現在就知道物體是否到達任何地方還爲時尚早。要檢測到這種情況,只要對象的事件處理在新線程中恢復,您就需要將對象的隊列中的一個元調用(請參閱this question)發佈到對象的隊列中。您還需要附加QThread::finished纔能有機會查看您的對象列表,並檢查它們中的任何一個是否存在於即將死亡的線程中。

但是,所有這些都涉及到:每個線程都需要自己的跟蹤器/過濾器對象,因爲事件過濾器必須存在於對象的線程中。我們可能會談論超過200行代碼來處理所有問題。

相反,您可以通過使用管理線程關聯的資源句柄利用RAII並保持你的對象(因爲它是一個!):

// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-track-38611886 
#include <QtConcurrent> 

template <typename T> 
class MainResult { 
    Q_DISABLE_COPY(MainResult) 
    T * m_obj; 
public: 
    template<typename... Args> 
    MainResult(Args&&... args) : m_obj{ new T(std::forward<Args>(args)...) } {} 
    MainResult(T * obj) : m_obj{obj} {} 
    T* operator->() const { return m_obj; } 
    operator T*() const { return m_obj; } 
    T* operator()() const { return m_obj; } 
    ~MainResult() { m_obj->moveToThread(qApp->thread()); } 
}; 

struct Foo : QObject { Foo(int) {} }; 

您可以通過值返回MainResult,但返回類型該函子必須明確給出:

QFuture<Foo*> test1() { 
    return QtConcurrent::run([=]()->Foo*{ // explicit return type 
     MainResult<Foo> obj{1}; 
     obj->setObjectName("Hello"); 
     return obj; // return by value 
    }); 
} 

或者,你可以返回調用MainResult的結果;這是一個函數本身,以節省一些輸入,但這可能被認爲是黑客,也許你應該將operator()()轉換爲一個簡稱的方法。

QFuture<Foo*> test2() { 
    return QtConcurrent::run([=](){ // deduced return type 
     MainResult<Foo> obj{1}; 
     obj->setObjectName("Hello"); 
     return obj(); // return by call 
    }); 
} 

雖然這是優選的構造對象與手柄一起,它也可以以一個實例指針傳遞到所述手柄的構造:

MainResult<Foo> obj{ new Foo{1} }; 
+0

使用處理線程關聯的句柄在這種情況下可能是最好的主意。謝謝。 – Aurelien

相關問題