最近因为TinyOS课中讲到无线通信模块的部分,要求是写一个winform用于接收数据并使用chart显示。
遇到了曾经遇到的问题,当时没有时间仔细研究,这次决定彻底把他解决。
实时显示的时候chart控件会报集合已修改的错误。
这时,chart的区域会变成一个红叉,并且除了重启程序以外无法修复。
我写了一个会报错的最简样例
//error private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { Random mrandom = new Random(); chart1.Series[0].Points.Clear(); for (int i = 0; i < 50; i++) chart1.Series[0].Points.AddY(mrandom.Next(20)); }
首先,我怀疑这个错误是因为处理数据耗时过多产生的,于是我写了一段使用timer快速添加删除数据的代码
private void timer1_Tick(object sender, EventArgs e) { Random mrandom = new Random(); chart1.Series[0].Points.Clear(); for (int i = 0; i < 50; i++) chart1.Series[0].Points.AddY(mrandom.Next(20)); }
运行很稳定,没有报错。
我怀疑是数据量不够大,又接了一个1e9次的循环,窗体变的非常卡,但是依旧很稳定,没有报错。
既然快速添加删除不会导致报错,那么真的就只是跨线程修改导致的问题了。
于是我为chart加上了锁
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { lock (chart1) { Random mrandom = new Random(); chart1.Series[0].Points.Clear(); for (int i = 0; i < 50; i++) chart1.Series[0].Points.AddY(mrandom.Next(20)); } }
可是,chart仍然很快就挂了。
这只能说明serialport的datareceive事件开了一个不安全的线程,所以我们不能把chart的处理放在datereceive中。
解决方案:timer是一个安全的线程,我们在datareceive中只处理数据,然后调用timer更新chart控件即可。
最终效果很稳定,没有再产生chart崩溃的现象。