Форум » » Обработка CHANGE BUFFER_INPUT » Ответить

Обработка CHANGE BUFFER_INPUT

gosha: Приветствую! Кусок кода: #DEFINE_CONSTANT STX 0xFC #DEFINE_CONSTANT ETX 0xFD #DEFINE_CONSTANT EXC 0xFE BUFFER_INPUT From_Device; Integer TempChar; CHANGE From_Device { print("Got data, len = %d",len(From_Device)); do { TempChar = getc(From_Device); print("TempChar = %02X",TempChar); } until(len(From_Device) = 0) } Все данные в From_Device обрабатываются в момент поступления. тенденции к росту буфера нет. Вставляем оператор switch: Change From_Device { print("Got data, len = %d",len(From_Device)); do { TempChar = getc(From_Device); switch(TempChar) { case(STX) : { print("Start sequence"); break; } case(ETX) : { print("End sequence"); break; } case(EXC) : { print("Escape character"); break; } default: { print("TempChar %02X",TempChar); } } // switch } until(len(From_Device) = 0); } По событию change обрабатывается только один символ из буфера, буфер имеет тенденцию к росту и дальнейшему переполнению. В чем моя ошибка?

Ответов - 2

Вячеслав: Уберите оператор break, тем более он тут не нужен

eoulianov: Привет! А сам-то как думаешь?) BREAK на этом наречии организует выход из циклов DO-UNTIL, FOR и WHILE, и никак не используется в SWITCH, поэтому STX/ETX/ESC рубят DO. В SIMPL+ при выполнении SWITCH выполняется только первый подходящий CASE, а если не подошел ни один - то DEFAULT (если есть). В общем SIMPL+ - диалект далёкий от канона C, и особой логики в расхождениях я не нашёл) Я бы хотел обратить внимание на обработку повторной входимости в конструкции CHANGE RX: может такое случиться, что один обработчик ещё не закончил выполняться, а новая его копия уже запустилась. Вот, например, что может случиться: пока вызывалась PRINT() потратилось время, и после "TempChar = getc(From_Device);" лимит времени потока вышел, система остановила поток обработчика CHANGE FROM_DEVICE и занялась чем-то более срочным; За это время что-то ещё принялось в буфер, соответственно произошло "событие" и была вызвана новая копия обработчика CHANGE FROM_DEVICE; эта новая копия ну давай работать - для начала она убила значение TempChar, записав вместо вынутого старым обработчиком символа новый (следующий) вынутый символ, и в последовательности PRINT() таким образом появилась дырка в один символ. Допустим, этому новому обработчику повезло и он дожевал весь буфер и мирно вышел. Теперь придёт время и запустится старый обработчик. он напечатает второй раз последний символ (ибо в TEMPCHAR сейчас лежит последний символ буфера, вытащенный другой копией обработчика - которая тоже его уже напечатала), и закончится. В боевой программе обычно всё оказывается хуже - теряются команды, зависает обработка, переполняется буфер. Чтобы избегнуть этой беды, нужно использовать семафоры (если вы пишете на Core3, посмотрите CMutex). Вторая беда при таком подходе - переполнение буфера из-за медленной обработки. Часто на старте программы, когда всё рефрешится, в буфер поступает много данных, и обработчик CHANGE RX может не успеть прожевать буфер и он будет расти и переполнится, а от этого может нарушиться обработка (потому что часть данных не попала в буфер, и парсер может заткнуться от неожиданных данных). Keep in mind. Третий кошмар - это ошибка исполнения, убивающая обработчик. Это может быть выход за границу диапазона в массивах, или сбойнувшая сетевая или файловая операция, которую затеял обработчик или вызванная из него функция. В Core3 с этим можно худо-бедно бороться с помощью TRY-CATCH, а в Series 2 обработчик при таких ошибках грохается и недообработанный буфер остаётся ждать следующего поступления.



полная версия страницы