我是一个小白,现在程序是需求是需要连续采集com口设备的数据,使用Windows.Forms.Timer定时向com口发送命令,然后在Comm_DataReceived里处理数据(包括和数据库交互),并更新界面,这里已经用了BeginInvoke更新UI。
设想的情况是,定义一个公共变量,timer每发送完一次,将公共变量赋值为false,Comm_DataReceived处理完数据后,将公共变量赋值为true,timer判读公共变量为true的话继续发送,为false的时候 不发送
现在遇到的问题就是程序运行一段时间后界面就卡死了,或者数据变化较大的时候也会卡死,请大神指条明路啊,谢谢;
是不是需要加个锁,Comm_DataReceived一般时异步回调的,如果没有锁的话,你的公共变量就会失控
加了lock锁,还是会卡死
@清岚思辰: 代码方便贴一下吗
@WmW: 其实过程并不复杂,请帮忙看看
private static bool inTimer = true;
private void Timer1_Tick(object sender, EventArgs e)
{
lock (ob)
{
if (inTimer)
{
inTimer = false;
//这里发送命令
}
}
}
void Comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock(obj)
{
//接收数据并处理
this.BeginInvoke((EventHandler)(delegate
{
//更新界面
}));
inTimer = true;
}
}
@清岚思辰: 为什么一个锁ob,一个锁obj啊,你的Timer1的频率是多少
@WmW: 我打错了,都是obj,频率0.2m
@清岚思辰: 看上去不是锁的问题,有可能是this.BeginInvoke异步还没执行完,你的inTimer = true了,导致又发送了请求,大量的this.BeginInvoke累计导致卡死了,你把inTimer = true放到this.BeginInvoke内部试试,待更新了Ui后再把inTimer置为true,如果能保证所有的操作执行完毕后再把inTimer=true,那就没必要加锁了
@WmW: 测试了一下,放进去还是会卡
@清岚思辰: 是刚运行就卡,还是随着时间越来越卡,如果是刚运行就卡,很可能是更新界面这块有问题
你用vs的f5运行会出现卡死现象吗?
会卡
.net版本如果高的话,可以收到数据后,Task.Factory.New(()=>处理。。。),处理过程中要更新界面的,直接 用Invoke即可。
如果版本低的话,你应该去降频,com有时候回传数据频率非常高,你必然要降。
硬件消息有一种模式是,如果你接收的数据只有最新的有效,那么你就不应该取所有的数据,而是取你需要 的时候最后一个。
你收到数据,把它们放到System.Collections.Concurrent.ConcurrentBag里面,下次来了,把旧的System.Collections.Concurrent.ConcurrentBag里面的覆盖掉。
你再起一个Timer,监控Bag里面的变化,如果有,则用业修改界面,这个Timer的频率是你可控的。
死锁了吧 或者是timer重入太快
如果是这样的话 可以在DataReceived开始的时候停到timer 结束后再次启动timer
还有 winform.timer 走的是ui线程 如果是发送指令时候的问题 可以在timer 执行的时候 在另一个线程发指令
愚见 无效勿喷