2012-04-26 29 views
2

我有一個gtkmm應用程序,我試圖把一些長時間運行的任務放到不同的線程中,這樣他們就不會鎖定GUI。這裏有一個教程,我根據我的設計:C++ Gtk線程。我做對了嗎?

http://www.velvetcache.org/2008/09/30/gtkmmglibmm-thread-example

我用油嘴::調度信號通知GUI線程,當工作完成或需要更新的東西,但我不知道如何在工作線程和GUI線程之間傳遞數據。到目前爲止,我一直在傳遞一個指向創建worker的類的指針,然後修改這個類的public成員,但是有些東西告訴我這不是最正確的做法。這裏有一個例子:

class Some_GUI_class 
{ 
public: 
    std::string thread_message; 

private: 
    Worker_class* worker; 

    void start_worker() 
    { 
     if (worker != NULL) return; 

     worker = new Worker_class(this); 
     worker->sig_message.connect(sigc::mem_fun(*this, &Some_GUI_class::display_message_from_thread); 
     worker.start(); 
    }   

    void display_message_from_thread() 
    { 
     some_label->set_text(thread_message); 
    } 
} 

class Worker_class 
{ 
public: 
    Worker_class(Some_GUI_class* gui_class) : gui_class(gui_class) 
    {} 

    void start() 
    { 
     thread = Glib::Thread::create(sigc::mem_fun(*this, &Worker_class::run), true); 
    } 

    Glib::Dispather sig_message; 

protected: 
    Glib::Thread* thread; 
    Glib::Mutex mutex; 

    Some_GUI_class* gui_class; 

    void run() 
    { 
     // ... 
     gui_class->thread_message = "Message from a thread!"; 
     sig_message();     
    } 

} 

這essentialy的作品,但我想如果GUI線程要同時修改thread_message會有問題嗎?這樣做是否安全?只要我確定變量只能由單個線程修改或者有更好的方法?

+0

我不是gtk專家,但據我記得你有一個UI的消息循環,所以你需要在主線程中捕獲這些消息,然後觸發事件,它的棘手。 – 2012-04-26 15:14:29

+0

@JakubOboza這是Glib :: Dispatcher所做的。 – ergosys 2012-04-26 21:46:14

回答

2

你有一個競賽條件。即使你的gui線程不修改thread_message,允許GUI線程讀取它,而另一個線程正在修改它不會給你長期的快樂。這是因爲std :: string本身不受多線程訪問的保護,並且有多個內部字段。如果一個線程正在修改其內部字段之一,而另一個線程正在讀取它們,則從第二個線程的角度來看,內部狀態將不一致。

您可以在GUI類中使用互斥鎖來保護對另一個線程可能訪問的變量的訪問。在get/set例程中鎖定和解鎖互斥鎖,並將這些例程用於所有其他訪問,以確保一次只有一個線程訪問或修改變量。

+0

謝謝。這就說得通了。你能否提供一個關於如何實現它的簡單代碼示例。我只需添加互斥體類成員並調用Glib :: Mutex :: Lock lock(mutex);在get/set方法的頂部? – jaho 2012-04-27 09:17:56

+1

基本上就是這樣。要明確一點,既然你在保護數據成員,你的互斥量應該是數據成員(而不是類(靜態)成員)。 – ergosys 2012-04-27 18:13:15

0

一般來說,互斥量的使用不足以實現所需的行爲。同一個工作線程(或另一個工作線程,如果有的話)可能想要發送另一個消息,而第一個線程還沒有被主線程處理。這就是爲什麼除了互斥之外,您還應該使用消息隊列(例如std::deque<std::string>類的對象)而不是僅使用std::string Some_GUI_class::thread_message變量來避免這種類型的消息丟失。