Не делайте этого в своей ветке:
lock (data) {
dati = data.ToList();
}
Вы используете очередь для двух разных целей; Вы используете его для передачи данных между двумя потоками, что хорошо; но вы также используете его в качестве буфера истории для предыдущих образцов данных. Это плохо.
Что вдвойне плохо, каждый раз, когда срабатывает таймер, вы блокируете очередь достаточно долго, чтобы потребитель мог скопировать, возможно, сотни данных, которые он ранее скопировал на более ранних отметках.
Это тоже плохо:
if (queue.Count <= 1000) {
queue.Enqueue(Frm_main.ComPh1.LeggiAnalogica(this.Address));
}
else {
queue.Dequeue(); <== THIS IS BAD!
queue.Enqueue(Frm_main.ComPh1.LeggiAnalogica(this.Address));
}
Одна из проблем заключается в том, что вы заставляете производителя управлять буфером истории (например, ограничивая длину очереди), но о длине заботится потребитель.
Другая проблема заключается в том, что производитель не блокирует очередь. Если какой-либо поток должен заблокировать структуру данных, то каждый поток должен заблокировать ее.
Производитель должен сделать только одно: он должен прочитать данные с датчика и поместить данные в очередь.
Очередь должна использоваться только для одной цели: для передачи новых данных между потоками.
Производитель должен заблокировать очередь достаточно долго, чтобы получить новые данные из очереди и скопировать их в свою собственную частную коллекцию.
Многопоточное программирование часто может быть нелогичным. Одним из примеров является; Если вы можете уменьшить количество времени, которое потоки тратят на доступ к общему объекту, на , увеличив объем работы, которую должен выполнять каждый поток, это часто повышает общую производительность программы. Это связано с тем, что блокировка обходится дорого, а доступ к областям памяти, которые были затронуты другими потоками, дорог.