我正在为I / O卡创建一个包装器。我有一个用于访问I / O卡的DLL库。目前,我的班级正在使用这个DLL打开卡,并读取/写入它的频道。 我正在使用while循环来连续读取输出端口,如下所示:
while (_enabled)
{
BitArray _currentState = ReadCurrentDiValue(); // read DI data with DLL
for (int i = 0; i < 8; i++)
{
if (_cardState[i] != _currentState[i])
{
_cardState[i] = _currentState[i];
OnBitChanged(new BitChangedEventArgs()
{
Port = (byte)i,
Value = _currentState[i]
}); // I want to fire this event asynchronously
}
}
}
此循环在分离的线程上运行。我的问题是,通过在事件处理程序中执行任何艰苦的工作,事件侦听器可能会阻止此线程运行。在这种情况下,可能无法识别输入到I / O卡的物理信号。 问题是,解决这个问题的正确方法是什么? 我有两个想法。 第一种是使用Task.Run简单地触发事件:
Task.Run(() => {
OnBitChanged(new BitChangedEventArgs()
{
Port = (byte)i,
Value = _currentState[i]
});
});
第二种方法是在OnBitChanged方法内调用委托上的BeginInvoke:
if (BitChanged != null)
{
var listeners = BitChanged.GetInvocationList();
foreach (var listener in listeners)
{
var eventHandler = (EventHandler) listener;
eventHandler.BeginInvoke(this, eventargs, ar =>
{
try
{
eventHandler.EndInvoke(ar);
}
catch
{
// ignore
}
}, null);
}
}
还有其他想法吗?我走错了路吗?
答案 0 :(得分:0)
两者几乎相同 - 都将处理程序发布到线程池。所以你最好使用Task.Run
,它有一个更好的界面。
最常用的方法是使用某种队列。这样,您就不会浪费超过必要的线程。这可能就像从队列中读取另一个线程并执行处理程序一样简单,也可以是可以与Task.Run
一起使用的自定义任务调度程序。线程池本身也是一个队列,但它引入了处理程序的并行性,这可能是不可取的 - 我希望您的应用程序协议可以在单个执行线程中工作。
最后,如果不读取数据会导致数据丢失,即使您将处理程序发布到另一个线程,您仍有机会丢失数据 - 最终,您需要一个可以自行缓冲的API。