我正在使用第三方库将数据从第三方输入设备传送到Windows窗体。我要做的是从设备收集输入数据,处理它并给定某些条件报告回Windows UI线程发生了什么。我无法访问第三方DLL的源代码,但我知道主要方法是在后台进程上,我无法将我的发现传回主UI线程我认为因为我没有创建它? / p>
Windows窗体:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// create instance of my listener
MyListener listener = new MyListener(this);
Controller controller = new Controller(listener);
}
}
扩展第三方类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 :(得分:0)
通常,尝试从处理UI的线程以外的线程访问UI对象是有问题的。这不仅仅是一个Windows问题,而是一种更普遍的模式。
通常的解决方案是设置某种形式的事件传播机制,其中包含更新UI所需的数据,并让主线程处理该任务。
让我们调用UI线程UI,然后调用后台线程BT。
您可以使用一个功能,将事件从BT发布到UI,然后阻止BT直到UI处理该事件。这是一个简单的系统,使用信号量阻止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;
}
};
这很简单,你可以看到,你只需要使用上面的模板和你需要的任何EVENT类。
我遗漏了处理互斥锁的代码,这取决于你想要依赖的api。
如上所述,UI必须仅轮询队列,即检查队列的大小,并在有可用的情况下取出事件。在BT方面,您需要做的就是在MyListener
课程中包含事件推送调用,而不是直接访问表单。
这种方法非常有效,让两个线程一起工作而不会相互踩踏。