【发布时间】:2019-06-17 07:50:53
【问题描述】:
我正在设置一个应用程序,它从称重传感器读取数据,并根据读取的数据实时中断电机的推力。必须从称重传感器获得高频读数。
我正在使用 c# 编程,我决定使用单独的线程从称重传感器获取数据。 我的问题是:如何以线程安全的方式使用线程中获取的数据?例如在图表中显示它们。
这是我调用的线程来获取队列中的数据。
Thread t = new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while (save_in_queue)
{
Thread.Sleep(1);
if (queue.Count <= 1000)
{
queue.Enqueue(Frm_main.ComPh1.LeggiAnalogica(this.Address));
}
else
{
queue.Dequeue();
queue.Enqueue(Frm_main.ComPh1.LeggiAnalogica(this.Address));
}
}
});
t.Name = "Queue " + this.name;
t.Start();
这是我用来关联线程填充队列和主队列的方法
public void SetData(Queue<int> q)
{
this.data = q;
}
这是我在主应用程序中用来设置系列数据的计时器
private void timer1_Tick(object sender, EventArgs e)
{
List<int> dati = new List<int>();
lock (data)
{
dati = data.ToList();
}
grafico.Series[serie.Name].Points.Clear();
for (int x = 0; x < dati.Count; x++)
{
DataPoint pt = new DataPoint();
pt.XValue = x;
pt.YValues = new double[] { dati.ElementAt(x) };
grafico.Series[serie.Name].Points.Add(pt);
}
}
此代码不起作用,因为有时我收到异常 dati = data.ToList(); 行上的“集合已修改;可能无法执行枚举操作”
我很清楚为什么我会收到此异常。但是如何解决呢?
我想避免使用过多的“锁”或过多的同步变量,以免降低采集性能,目前这非常好。
【问题讨论】:
-
也许通过类+公共变量和/或方法?
-
出现异常是因为你没有在线程中锁定队列。这个
this.data = q;只是参考的副本。整个区块if (queue.Count <= 1000)......必须在锁内。 -
如果线程内的锁率太高但您仍然需要这些值,您可以先将它们添加到本地队列中,然后将它们批量添加到共享队列中。 (例如每 20 个值)(
queue.AddRange())但是当队列不是列表时,这不起作用。
标签: c# multithreading collections thread-safety