2012-12-14 58 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课程中包含活动推送呼叫,而不是直接访问该表单。

这种方法非常有效地让两个线程一起工作,而不用踩在彼此的脚趾上。