В основном это проблема производитель-потребитель, так что это должно быть основой для общего дизайн.
Вот некоторые мысли по этому поводу:
a) Буфер FIFO (очередь)
Прежде всего, у вас должен быть экземпляр потокобезопасной очереди (буфера FIFO) для каждого экземпляра вашего класса. Один поток будет получать данные и заполнять их, в то время как другой будет читать данные потокобезопасным способом. Это означает только то, что вам придется использовать блокировку для каждой операции постановки/удаления из очереди.
FIFO Queue позволит вам одновременно обрабатывать данные в рабочем потоке и заполнять их из коммуникационного потока. Если вам нужно получить много данных, вы можете удалить некоторые данные из очереди в рабочем потоке и проанализировать их до того, как все они будут получены. В противном случае вам нужно будет подождать, пока все данные не будут получены, чтобы проанализировать их все сразу. В большинстве случаев вы не знаете, сколько данных вы должны получить, пока не начнете анализировать их.
b) Рабочий поток ожидает данных
Я бы создал рабочий поток, который будет ждать сигнала о получении новых данных. Вы можете использовать ManualResetEvent.WaitOne(timeOut) для тайм-аута на случай, если какое-то время ничего не произойдет. Когда данные будут получены, вам придется проанализировать их на основе вашего текущего состояния, так что это будет реализация конечный автомат.
c) Абстракция порта
Чтобы обрабатывать разные типы портов, вы можете обернуть свой последовательный порт внутри интерфейса, который может иметь как минимум эти методы (могу я что-то забыть):
interface IPort
{
void Open();
void Close();
event EventHandler<DataEventArgs> DataReceived;
void Write(Data data);
}
Это поможет вам отделить конкретный код связи от конечного автомата.
ПРИМЕЧАНИЕ. (согласно Microsoft) Событие DataReceived не гарантируется для каждого полученного байта. Используйте свойство BytesToRead, чтобы определить, сколько данных осталось прочитать в буфере. Таким образом, вы можете создать свою собственную реализацию IPort, которая будет регулярно опрашивать SerialPort, чтобы гарантировать, что вы не пропустите ни одного байта (есть вопрос о SO, который уже решает эту проблему).
г) Получение данных
Чтобы получить данные, вам нужно будет прикрепить обработчик для события IPort.DataReceived (или SerialPort.DataReceived, если вы его не упаковываете) и поставить полученные данные в очередь внутри обработчика. В этом обработчике вы также должны установить упоминание ManualResetEvent для уведомления рабочего потока о получении новых данных.
person
Groo
schedule
24.03.2009