使用工作线程的多线程库无法与UI线程通信



我正在使用第三方库将数据从第三方输入设备传输到Windows窗体。我想做的是从设备收集输入数据,进行处理,并在特定条件下向Windows UI线程报告发生了什么。我无法访问第三方DLL的源代码,但我知道主方法在后台进程中,我无法将我的发现传达回主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类,它扩展了第三方类Listener:

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线程对话的尝试都会使应用程序崩溃,并给我无效的内存位置错误。

如有任何帮助,我们将不胜感激。

通常,尝试从处理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类中包含事件推送调用,而不是直接访问表单。

这种方法非常有效,可以让两个线程在不踩对方脚趾的情况下一起工作。

相关内容

  • 没有找到相关文章

最新更新