2012-12-14 55 views
1

我正在使用第三方庫將數據從第三方輸入設備傳遞到Windows窗體。我期望做的是收集來自設備的輸入數據,對其進行處理,並給出某些條件向Windows UI線程報告發生的情況。我沒有訪問第三方DLL的源代碼,但我知道主要方法是在後臺進程,我不能將我的發現傳回給主UI線程,我想是因爲我沒有創建它?使用工作線程的多線程庫無法與UI線程通信

Windows窗體:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     // create instance of my listener 
     MyListener listener = new MyListener(this); 
     Controller controller = new Controller(listener); 
    } 
} 

myListener的類,它擴展了第三方類監聽器:

public class MyListener : Listener 
{ 
    public Form1 form; 
    private Frame frame; 

    // overloaded constructor 
    public LeapListener(Form1 f) 
    { 
     form = f; 
    } 

    /// <summary> 
    /// onFrame is the main method that runs every milisecond to gather relevant information 
    /// </summary> 
    public override void onFrame(Controller controller) 
    { 
     // Get the most recent frame and report some basic information 
     frame = controller.frame(); 
    } 
} 

的問題是,我可以回來從任何地方myListener的類內進行通信的主UI線程,但我無法通過onFrame方法進行反饋,因爲它在後臺線程上運行。反正有沒有從我沒有創建的後臺線程中獲得主線程?

我已經試過ReportProgress,我已經嘗試創建myListener的所有嘗試去跟從onFrame主UI線程應用程序崩潰,並給我無效的內存位置錯誤的事件。

任何幫助將不勝感激。

+0

'有沒有辦法從我沒有創建的後臺線程中獲得主線程? - 當然,最重要的問題是你在C++/C#中有什麼可用的東西。通常,這是語言/庫提供的Invoke/BeginInvoke方法或SendMessage/PostMessage API。你有沒有? –

+0

'Controller'對象是否在不同的線程中運行? – didierc

回答

0

通常情況下,試圖從一個比處理其他UI線程訪問UI對象是有問題的。這不是一個僅限Windows的問題,而是一個更一般的模式。

通常的解決辦法是設置某種形式的事件傳播機構,其將包含更新UI所需的數據,而讓主線程處理該任務。

讓我們調用UI線程UI和後臺線程BT。

你可以有哪些方式發佈事件從BT到UI,然後直到事件被處理,UI BT阻斷的功能。這是一個簡單的系統,使用信號量來阻止BT,直到UI釋放它。這樣一個系統的優點是它很簡單,你不需要一次處理兩個以上的事件。缺點是如果事件需要很長時間才能處理,應用程序的採樣分辨率會非常差。 另一種(也是更好的)方法是創建一個事件隊列,讓BT發佈到它,然後用UI進行輪詢以更新它自己。它需要更多的工作,但它對UI長時間的方式更具彈性。

對於第二種方法,你必須建立一個格式,爲您的活動,建立一個共享和BT和UI,和其他地區之間的互斥鎖保護隊列應該是很容易的事情。

隊列可能是類似以下內容:

#include <queue> 


template <typename EVENT> 
class EventQueue { 
    protected: 
    typedef EventQueue<EVENT> self_type; 
    typedef std::queue<EVENT> queue_type; 
    Mutex m_; 
    queue_type q_; 
    void lock(){ 
     // lock the mutex 
    } 
    void unlock(){ 
     // unlock the mutex 
    } 
    public: 
    EventQueue() { 
     // initialize mutex 
    } 
    ~EventQueue() { 
     // destroy mutex 
    } 

    void push(EVENT &e){ 
     lock(); 
     q_.push(e); 
     unlock(); 
    } 
    EVENT &pop(){ 
     EVENT &e; 
     lock(); 
     e = q_.pop(); 
     unlock(); 
     return e; 
    } 
    int size(){ 
     int i; 
     lock(); 
     i = q_.size(); 
     unlock(); 
     return i; 
    } 
}; 

這是因爲你可以看到很簡單,你只需要你需要的任何事件類使用上面的模板。

我已經離開了代碼處理互斥體,這取決於你想依靠其API。 如上所述,用戶界面只能輪詢隊列,即檢查隊列的大小,如果有可用的事件則取出事件。在英國電信方面,您需要做的只是在您的MyListener課程中包含活動推送呼叫,而不是直接訪問該表單。

這種方法非常有效地讓兩個線程一起工作,而不用踩在彼此的腳趾上。