Поскольку связь через последовательный порт является асинхронной, я рано понял в своем проекте, связанном с обменом данными с устройством RS 232, что мне потребуется фоновый поток, постоянно считывающий порт для полученных данных. Теперь я использую IronPython (.NET 4.0), поэтому у меня есть доступ к классному классу SerialPort, встроенному в .NET. Это позволяет мне писать код так:
self.port = System.IO.Ports.SerialPort('COM1', 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One)
self.port.Open()
reading = self.port.ReadExisting() #grabs all bytes currently sitting in the input buffer
Достаточно просто. Но, как я уже говорил, я хочу постоянно проверять этот порт на наличие новых данных по мере их поступления. В идеале, я бы хотел, чтобы ОС говорила мне каждый раз, когда ожидают данные. Что бы знать, мои молитвы были услышаны, предусмотрена DataReceived
встреча!
self.port.DataReceived += self.OnDataReceived
def OnDataReceived(self, sender, event):
reading = self.port.ReadExisting()
...
Жаль, что это ничего не стоит, , потому что это событие не гарантированно будет вызвано !
Событие DataReceived не гарантируется для каждого полученного байта.
Итак, вернемся к написанию потока для слушателя. Я сделал это довольно быстро с BackgroundWorker
, который просто вызывает port.ReadExisting()
снова и снова. Он читает байты по мере их поступления, а когда он видит строку, заканчивающуюся (\r\n
), он помещает то, что он прочитал, в linebuffer
. Затем другие части моей программы смотрят на linebuffer
, чтобы увидеть, есть ли какие-либо полные строки, ожидающие использования.
Теперь, это классическая проблема производитель-потребитель , очевидно. Производитель - BackgroundWorker
, помещающий полные строки в linebuffer
. Потребитель - это некоторый код, который потребляет эти строки из linebuffer
как можно быстрее.
Однако потребитель вроде бы неэффективен. Прямо сейчас он постоянно проверяет linebuffer
, каждый раз разочаровываясь, обнаруживая, что он пуст; хотя время от времени находит линию, ожидающую внутри. Как лучше всего оптимизировать этот процесс, чтобы потребитель проснулся только при наличии доступной линии? Таким образом, потребитель не будет постоянно обращаться к linebuffer
, что может вызвать некоторые проблемы с параллелизмом.
Кроме того, если есть постоянный и более простой способ чтения с последовательного порта, я открыт для предложений!