Статья
Версия для печати
Обсудить на форуме
Программирование Real-Time - организация потокового приема с СОМ порта.



В прошлый раз мы рассмотрели, как происходит оценка системы, что это такое, а также имеем на руках обширный список таких систем. Что делать, если, несмотря на их обилие, приходится работать с такими системами, как WinCE?

Для приведенного примера подойдет любая задача, связанная с приемом данных на COM порту или схожим с ним коммуникационным портом.

На рисунке 1 показана схема такого решения:



Рисунок 1.

Два круга - это два потока библиотеки протокола обмена данными.
Предполагая, что с другой стороны порта находится некий асинхронный прибор, присылающий пакеты данных в произвольное время, мы обязаны организовать один ждущий поток (справа на рисунке), который будет ждать события прихода данных.

По приходу таковых идет забор данных во внутренний буфер памяти (на рисунке не отображен). Забор данных вполне может идти с первоначальной оценкой, такой как:
выборка комбинаций для записи, прием только нужных пакетов, и т.д.

Так как время реакции критично, а объем данных не известен заранее, то буфер должен быть достаточен для максимально возможного объема данных, а алгоритм не должен заниматься отработкой самих данных.

После завершения приема пакета мы входим в View - проводим краткий анализ, если это необходимо (чаще уже нет), и пишем в общую область памяти существующий пакет в секторе между lock/unlock для запрета записи или чтения в этот момент другим потоком.

После новой записи создаем событие для сообщения второму потоку о готовности данных и входим в состояние ожидания новых данных.

Тот же алгоритм, только в расширенном виде, видим и во втором потоке. В этом случае основной задачей является только расшифровка нужных данных и запись уже расшифрованной информации в память для аппликации.

Получив сообщение о событии, второй поток вычитывает в lock/unlock блоке, данные, записанные в общую с первым потоком память. Далее отрабатывает необходимые действия с данными и выкладывает их в другом блоке lock/unlock в память для программы. После этого вновь становится в ожидание. Расшифрованные данные с помощью механизма API считываются из второй области памяти по мере надобности.

Таким образом, всегда можно быть уверенным, что считываются данные последние из полученных и, соответственно, реагировать. В API для чтения обязательно должен учитываться второй lock/unlock, дабы не считать данные во время записи.

Если имеется необходимость для постоянной переброски данных, так чтобы и аппликация не самостоятельно запрашивала данные, а получала их в момент, когда они только что получены, то в API необходимо встроить заказ сообщения от второго потока - передаваемое в аппликацию. Тогда, по его получении, можно будет сразу считывать все необходимое. По возможности стоит не копировать данные по полям структур с помощью присваивания, а делать прямое копирование памяти (memcopy), оно действует намного быстрее, что критично при насыщенном потоке.

Организация потока программы, в которой будет ожидание, можно устраивать с помощью такого же механизма WAIT или встроенными средствами OS, типа WM_MESSAGE, - если это не мешает работе программного пользовательского интерфейса.

Естественно, ставится вопрос, зачем 2 потока внутри библиотеки и так сложно организованный процесс двойной передачи. Объясню, что при работе такого варианта, при правильно написанной библиотеке, практически исключается возможность накладки процесса чтения и записи в одну и ту же область. Достигается гибкость кода - его можно подключать независимо, используя API, и не волноваться за накладки.

При встраивании второго потока в уровень программы мы оказываемся в ситуации, когда ее код и процессы защиты встроены в наш программный код и зависимы от типа пакета, который принимается нами. Вторая похожая задача будет опять писаться заново.

В варианте, описанном здесь, мы соблюдаем все условия инкапсуляции и полностью отключаем задачу аппликативного уровня от коммуникационного.

Стоит учесть, что с сокетами такой тип организации не может быть осуществлен полностью. Вернее, не является оптимальным в связи с многочисленными сокетами, которые могут быть отслежены в select и должны обрабатываться соответственно.


Автор: Гром
Версия для печати
Обсудить на форуме