LINUX.ORG.RU

boost::asio::serial_port - асинхронное чтение с ограничением по таймеру

 , , ,


1

2

Всем привет. Решил тут поковырятся в крестах на злобу дня. Но нигде не могу найти правильный рецепт приготовления. Есть грамотные кто может подсказать по сабжу?

★★★★★

Последнее исправление: yax123 (всего исправлений: 1)

Ответ на: комментарий от rumgot

Там есть ещё подводный камень, run не пашет в отдельном потоке, и если очередь опустела и так постояла - то новые задачи не обрабатываются надо contex.reset делать

Silerus ★★★★
()
Ответ на: комментарий от rumgot

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

Silerus ★★★★
()
Последнее исправление: Silerus (всего исправлений: 1)
Ответ на: комментарий от Silerus

Ну тут логично. Вроде в документации boost.asio про что-то такое указано, если не путаю.

Но я тут думаю, что обработка не должна прерываться постоянно. Пусть себе висит в отдельном потоке и читает байтики. Только в случае, когда что-то пошло не так, нужно рубить все.

rumgot ★★★★★
()
Ответ на: комментарий от yax123

Понял косвенно, что поток это разгребает один. Тогда возникает закономерный вопрос - ты собираешься чего-то делать кроме чтений и репорта статуса в этом потоке? Если нет - поясни чем не подходит подход с run_for вместо run_one.

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

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

можно запустить через strace сишную программу и крестовую с asio и посмотреть, где какая разница в системных вызовах и их параметрах

Harald ★★★★★
()
Ответ на: комментарий от Silerus

вопрос на засыпку.

Опять взвожу async_wait (с таймаутом 1500мкс), asyn_read. Вызываю run_one. и через 5 мкс мне прилетает калбек таймера (с ошибкой system:125, если это важно). А иногда повторно еще через 7 мкс примерно (с той же ошибкой). А потом прилетает калбек чтения (пустой), и потом уже нормальный калбек таймера через нормальное время.

Есть подозрение, что перед выходом предыдущего вызова не происходит отмена операций. И вот она меня догоняет на следующей итерации. Так возможно? Понятно, что все вызовы cancel в коде есть.

Ну и вот такой преждевременный калбек от таймера прилетает, только тогда когда на предыдущей итерации было удачное чтение из порта.

yax123 ★★★★★
() автор топика
Последнее исправление: yax123 (всего исправлений: 1)
Ответ на: комментарий от yax123

Оки.

Но раз поток один - чем собственно не устраивает deadline_timer + cancel? Просто тебе не надо городить огород с твоим run_one, нужно просто запустить run и сделать нормальную машину состояний для своих протоколов. Это с несколькими потоками там есть некий секс, если ты хочешь агрессивную работу с каналом например.

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от yax123

Посмотри strace станет понятней. Насколько я помню, io_service это такой костыль построенный на ppoll/epol_wait/io_cp где вместо кондиционной переменной, используется фейковый дескриптор чуть ли не сокета, что бы будить эту очередь на post.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Но раз поток один - чем собственно не устраивает deadline_timer + cancel? Именно это я и горожу. с deadline_timer + cancel.

run

The run() function blocks until all work has finished and there are no more handlers to be dispatched, or until the io_service has been stopped. 

я это даже гуглетранслейтом переводил. run - заблокируется на все время пока не сработает и чтение и таймер. Или это все херня?

Смысл какой. Я делаю класс-оберту вокруг boost::asio. делаю метод:

std::size_t read(char * data, const std::size_t size, const pt::time_duration timeout, ReadResult &res)

И желаю чтобы он либо сразу вернулся с порцией данных в буфере либо по таймауту. При этом чтобы не терял данные из порта.

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

Вот из-за cancel все и происходит (да действительно догоняет, сам наблюдал подобную фигню, при реконекте получал следом read timeout ну и закрытие транспорта соответственно, я так понимаю что при cancel задача помечается как завершённая), их вообще не должно быть, если мы не собираемся закрывать транспорт совсем по какой либо из причин, на вроде пользователь вызвал дисконнект

Silerus ★★★★
()
Ответ на: комментарий от Silerus

да действительно догоняет, сам наблюдал подобную фигню,

ну значит это мне не кажется. уже утешение.

ну и как тогда эту поделку использовать?

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

Вот прям сейчас не подскажу, весь код на работе, а я уже дома. Завтра выложу для тебя весь код клиента ( он - tcp/ip, но сам понимаешь, надо только транспорт заменить), он не сильно отличается от примера, но я там использую poll, у меня там еще графика крутилась. По поводу таймеров их не надо отменять - их надо переназначать - т.е dedline.async_wait() - не создает задачу контексте только в первый раз (если таймер не завершиться по timeout), а дальше переустанавливает таймер.

Silerus ★★★★
()
Ответ на: комментарий от Silerus

По поводу таймеров их не надо отменять

ну а если за 3 мкс я вычитал весь запрошенный размер и вышел. зачем мне там тикающий таймер?

yax123 ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

io_service это такой костыль построенный на ppoll/epol_wait/io_cp где вместо кондиционной переменной, используется фейковый дескриптор чуть ли не сокета, что бы будить эту очередь на post.

отсюда вопрос, нафиг этот костыль нужен? только для единообразия, или его для сериала вообще никто никогда не тестировал?

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

А, про класс обёртку это важное замечание. Ну как бы, в таком single shot варианте run_for это прямо то, что доктор прописал. Я то думал там речь про эффективный i/o какой-то, про подружить в одном цикле два потока данных и машина состояний для протокола. Вот тебе псевдокод:


bool had_read = false;
port.async_read([&had_read]{if(!error) had_read = true;});
ioservice.run_for(42ms);

if(had_read)
    return data;
else 
    return timeout;

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

Конкретно с последовательными портами я никогда не работал плотно, разве что в студенческие годы. Вообще - схема на самом деле вполне эффективная, я видел решения которые с IP камер обрабатывали очень хорошо видео в одном цикле обработки событий с GUI на одном потоке.

Я честно думал как-бы сделать лучше при условии что можно свободные функции докидывать в события и не придумал. Видимо как и авторы буст.

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

Это тоже важное замечание :)

Тогда deadline_timer с таким же флагом и отмена чтения если флаг не был взведён.

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

давай еще раз, твоя задача читать данные, если на порт не приходят данные в течение timeout - даем пинок под зад твоим slaves - я правильно тебя понимаю? Если так то должно быть что то вроде: Запускаем таймер ожидания данных, если данные пришли, а таймер не отсчитал до конца - то отправляем данные на обработку, перезапускаем таймер и ждем следующий пакет, иначе получаем timeout и выполняем внештатные операции - все верно? если так то зачем нам отменять таймер?

Silerus ★★★★
()
Ответ на: комментарий от pon4ik

Тогда deadline_timer с таким же флагом и отмена чтения если флаг не был взведён.

не уловил идеи. что за флаг? и что значит взведен?

yax123 ★★★★★
() автор топика
Ответ на: комментарий от Silerus

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

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

Вернёмся к псевдокоду:

ioservice s;

bool had_read = true;

deadline_timer.async_wait([&had_read]{if (!error) had_read = false;}

port.async_read();

s.run_one();

if (had_read) 
    return data;
else
    return timeout;

pon4ik ★★★★★
()
Ответ на: комментарий от Silerus

если данные пришли, а таймер не отсчитал до конца - то отправляем данные на обработку, перезапускаем таймер и ждем следующий пакет

все так.

щас попробую убрать сброс таймера.

вобщем проблема с несброшенным таймером в том, что когда он прилетает раньше времени, как побочный эффект у меня теряются данные. Хотя я этот скорострел отлавливаю и ничего в этот момент не делаю.

yax123 ★★★★★
() автор топика
Ответ на: комментарий от Silerus

Задача уровня «сделать как в Qt» :)

Смысл какой. Я делаю класс-оберту вокруг boost::asio. делаю метод:

std::size_t read(char * data, const std::size_t size, const pt::time_duration timeout, ReadResult &res)

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Задача уровня «сделать как в Qt» :)

Не смотрел как это в qt. а когда смотрел, serial в qt еще не завезли. Но если они пошли по такому же пути, это навевает на мысли, что это не моя извращенная хотелка.

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

Аааа. Ну тогда надо в цикл ещё положить и таймеру уменьшать таймаут пока значение хвостика не получится нулевым или отрицательным.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Аааа. Ну тогда надо в цикл ещё положить и таймеру уменьшать таймаут пока значение хвостика не получится нулевым или отрицательным.

дык может вообще все на асме в инлайне написать? че мелочится то.

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

А я тоже не смотрел как в Qt, но судя по файловому интерфейсу это похоже. Просто у тебя плохой API. Плохой вот почему - когда читаешь сигнатуру, ожидаешь следующего поведения «подождать таймаут, если пришли данные - считать всё что пришло и выйти». А по-факту оно должно делать - «считать всё, что придёт в течении таймаута и вернуть ошибку если не пришло ничего». Прям супер удивляющий интерфейс.

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

Какие задачи, такие и методы их решений. Ты таки хрень какую-то загадал. Она может и не хрень в терминах твоей бизнес логики, но в терминах ввода вывода будет сбивать с толку всех кто не в теме твоих локальных соглашений.

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

У них в примере и сделано практически как в Qt, только очередью событий занимается ихний io_context (io_Service -устарел). Да вроде говорит что я его правильно понял. У асио есть большая проблема, очень однобокие примеры, которые путают, а не помогают разобраться, stackoverflow - завален подобными вопросами.

Silerus ★★★★
()
Ответ на: комментарий от pon4ik

одождать таймаут, если пришли данные - считать всё что пришло и выйти»

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

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

А, тогда я не правильно понял тот коммент. Если операция чтения только одна, смотри крайний псевдокод который я выше закинул оно должно работать. Просто io_service на стеке проще создавать пока это не станет узким местом(скорее всего до никогда судя по таймаутам).

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

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

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

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Так, а в каком таком API оно есть готовое? Вот он такой API как раз и делает :)

pon4ik ★★★★★
()
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от Silerus

Про run_for я ещё на первой странице закинул, но шо io_context, шо конкретно эта его функция отсутсвуют в нужной версии буста в связи с её тухлостью :)

pon4ik ★★★★★
()
Ответ на: комментарий от Silerus

Справедливости для, конкретно для последовательных портов есть возможность задать таймауты на чтение на уровне системных вызовов. Но - в секундах, лол.

pon4ik ★★★★★
()
Ответ на: комментарий от Silerus

Да, прогнал не в секундах а в десятых долях секунды. Ошибся на порядок. Но API такой себе - во-первых непортабельно, во-вторых странные единицы измерения, в третьих - сам таймаут ограничен ~20секундами. Ох уж этот волшебный мир последовательных портов, лол.

pon4ik ★★★★★
()
Ответ на: комментарий от yax123

При этом аналогичный код на сишечке отлично работает уже год.

Ну и за каким хреном тебе асиошная шизофрения?

Вот я и хочу понять, что там такого в калбеке чтения и ране происходит,

Код открыт же.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

Код открыт же.

я тут за бесплатными ответами пришел, а не за советом в исходниках копаться

Ну и за каким хреном тебе асиошная шизофрения?

чувак, тут не лолксы.

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

yax123 ★★★★★
() автор топика
Ответ на: комментарий от yax123

я тут за бесплатными ответами пришел,

Я тебе его и даю (и советую взять, пока я добрый) - иди читай исходники.

интересно, если на тебя модера натравить

Надеешься, что он потрёт весь тред, чтобы скрыть твои обосрамсы? Напрасно.

LamerOk ★★★★★
()
Ответ на: комментарий от yax123

Петиция супротив поправок об ограничении просветительской деятельности (комментарий)

Для великовозрастного тролля сообщаю:

  1. У тебя в стране использовано химическое оружие (которого нет с 2017, лол).
  2. У тебя в стране без суда и следствия попытались казнить человека.
  3. У тебя в стране не возбуждают дело против тех, кто действовал в пункте 2.
  4. У тебя в стране дают безграничную власть силовикам над обывателем.
  5. У тебя в стране пользователи ололоЛинукса обеспечивают чебурнет. …. Ты тут ….
  6. А сейчас об этом и говорить будет нельзя. Нельзя будет говорить про «не то» о второй мировой и прочем, в лекциях по истории. Чтобы чел просто рассказал о ЯП Python, а не о ОП ЯР (привет чудакам) надо будет писать местному майору, чтобы он одобрил.

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

Местные, у кого мозги есть, детей уже вместе с собой перебросили за забор. Остальные же привязаны местом работы и/или родственниками.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.