Russian Qt Forum

Программирование => С/C++ => Тема начата: juvf от Январь 27, 2015, 08:24



Название: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 08:24
Есть обмен между двумя процессами через pipe fifo.
Код:
int fifo_out = open (pathname, O_RDONLY);
int bytes = read(fifo_out, (void *)&info_data, sizeof(InfoData));

как выйти из read, если в течении 70 мс в pipe не поступили данные?


Название: Re: read() Выход из чтения по таймеру
Отправлено: Fat-Zer от Январь 27, 2015, 08:58
используй poll(2) или select(2) и читай только когда данные появятся...

Другие варианты решения:
 - можно открывать c [или ставить позже] O_NONBLOCK. далее фантазировать около sleep'ов и ручного управления таймерами
 - [относительно извращённый] можно подписаться на SIGALRM с помощью alarm(2) или более новых интерфейсов. и плясать от этого. read() должен будет возвращаться c EINTR.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 09:50
используй poll(2) или select(2) и читай только когда данные появятся...

вроде то что нужно.... но при обмене через fifo pipe может быть такое что жду пулом или селектом данных. должно прийти 10 байт. я вышел из селекта по событию "есть данные для чтения". Начинаю ридом читать, а там данные не все, только 8 байт, остальные не пришли (такое бывает при обмене через UART). Отправитель всегда шлёт по 10 байт. гарантированно. Нужно мне, при такой организации обмена проверять, что если после селекта рид вычитал 8 байт, то ещё раз зайти в селект и попытаться дополучить 2 байта, если не пришли, то бракую пакет?


Название: Re: read() Выход из чтения по таймеру
Отправлено: Fat-Zer от Январь 27, 2015, 10:12
вроде то что нужно.... но при обмене через fifo pipe может быть такое что жду пулом или селектом данных. должно прийти 10 байт. я вышел из селекта по событию "есть данные для чтения". Начинаю ридом читать, а там данные не все, только 8 байт, остальные не пришли (такое бывает при обмене через UART). Отправитель всегда шлёт по 10 байт. гарантированно. Нужно мне, при такой организации обмена проверять, что если после селекта рид вычитал 8 байт, то ещё раз зайти в селект и попытаться дополучить 2 байта, если не пришли, то бракую пакет?
да, всё так.
FYI: но если нужно жёстко следить, чтобы при повторном select'е у него был только остаток времени, то придётся делать это ручками... полагаться на то что select изменит таймер не стоит.


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 10:14
FYI: но если нужно жёстко следить, чтобы при повторном select'е у него был только остаток времени, то придётся делать это ручками... полагаться на то что select изменит таймер не стоит.
Такое проще делать отдельным таймером.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 10:16
да, всё так.
FYI: но если нужно жёстко следить, чтобы при повторном select'е у него был только остаток времени, то придётся делать это ручками... полагаться на то что select изменит таймер не стоит.
плохо. лучше наверно таймер задавать на ожидание 1 байта и принимать по 1 байту


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 10:28
плохо. лучше наверно таймер задавать на ожидание 1 байта и принимать по 1 байту
Зачем? Вы установили таймер на 70 мс и запустили цикл пулинга. Данные могут прийти несколькими кусками. Если успели все принять, до срабатывания таймера - все ок, таймер сработал раньше - не ок.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 11:30
плохо. лучше наверно таймер задавать на ожидание 1 байта и принимать по 1 байту
Зачем? Вы установили таймер на 70 мс и запустили цикл пулинга. Данные могут прийти несколькими кусками. Если успели все принять, до срабатывания таймера - все ок, таймер сработал раньше - не ок.

ээээ.... не понял. на русском языке не понятно, можете на с++ тоже самое сказать?


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 11:42
ээээ.... не понял. на русском языке не понятно, можете на с++ тоже самое сказать?
На чем вам будет удобней: на Qt или boost?
Или рекомендую для организации пулинга использовать libev. Там тоже есть таймеры.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 12:11
да хоть на чем. и причем здесть буст или кьют? вы предлагаете внешний таймер использовать? костыльный вариант по мойму. Покажите как это будет с внешним таймером выглядеть?


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 12:25
и причем здесть буст или кьют?
В них уже есть пулинг и таймеры. Как я уже написал выше, есть еще несколько удобных и быстрых библиотек для этого.
Но это несложно и завелосипетить самому, конечно если есть свободное время.

вы предлагаете внешний таймер использовать? костыльный вариант по мойму.
Что значит внешний таймер?
Кто-то должен засекать время, таймер для этого подходит лучше всего.

Покажите как это будет с внешним таймером выглядеть?

Да все элементарно.

Код
C++ (Qt)
// Запускается таймер на необходимый интервал, когда он срабатывает, вызывается функция onTimeout
// Запускается пулинг, при появлении данных для чтения, вызывается функция onReadyRead
 
void onTimeout()
{
   // Здесь мы знаем, что время вышло, а данные не пришли
}
 
void onReadyRead()
{
   // Доступны не все данные, выходим и ждем еще
   // (или вычитываем все доступные во внутренний буфер)
   if( bytesAvailable() < 10 )
       return;
 
   // Все данные доступны - останавливаем таймер
   timer->stop();
 
   // Вычитываем и/или обрабатываем данные
}
 


Название: Re: read() Выход из чтения по таймеру
Отправлено: qate от Январь 27, 2015, 12:36
если именно обмен с uart, то почему не через QSerialPort ?


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 12:38
если именно обмен с uart, то почему не через QSerialPort ?

обмен c другой программой через fifo pipe


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 12:48
если именно обмен с uart, то почему не через QSerialPort ?
В линуксе практически для любого хендла можно использовать QSocketNotifier, с пайпами в том числе.


Название: Re: read() Выход из чтения по таймеру
Отправлено: qate от Январь 27, 2015, 13:01
тогда наверно неблокирующий read поможет


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 13:04
Что значит внешний таймер?
Кто-то должен засекать время, таймер для этого подходит лучше всего.
Это значит то, то например при чтении из уарта ни каких специальных таймеров не создается. после настройки таймаутов read блокирует выполнение потока на ожидании всех байт, либо до тайм аута. В прицепе тоже самое ожидание можно организовать селектом и пулом без всяких внешних таймеров.

Цитировать
// Доступны не все данные, выходим и ждем еще
а сколько ждать?


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 13:06
тогда наверно неблокирующий read поможет
так наоборот нужно заблокировать до прихода пакета или до таймаута.


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 13:10
Это значит то, то например при чтении из уарта ни каких специальных таймеров не создается. после настройки таймаутов read блокирует выполнение потока на ожидании всех байт, либо до тайм аута. В прицепе тоже самое ожидание можно организовать селектом и пулом без всяких внешних таймеров.
Да ради Бога, таймер это удобная сущность для учета времени и не более.
Вы можете просто сохранять текущее время до начала ожидания данных и сравнивает его с текущем при каждом срабатывании того же селекта.

а сколько ждать?
Следующего цикла пулинга.


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 13:11
так наоборот нужно заблокировать до прихода пакета или до таймаута.
Блокировать не обязательно, главное дождаться или одного или другого события.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 13:22
так наоборот нужно заблокировать до прихода пакета или до таймаута.
Блокировать не обязательно, главное дождаться или одного или другого события.

нужно блокировать. в этом фишка. иначе можно просто

while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ); лишняя нагрузка.

Цитировать
Следующего цикла пулинга.
что получается в вашем алгоритме: запустили таймер на 70 мс. запустили пулинг на 70мс. ждём.... через 50 мс получили кусок пакета... проверяем bytesAvailable() < 10 и запускаем следующий цикл пулинга... т.е. на 70 мс. больше байт допустим нет в пайпе. пулинг ждёт свои 70 мс. срабатывает таймер и вызывает onTimeout(). ...... вот тут как-то не всё элементарно.... что дальше? как onTimeout прервёт пулинг, которому ещё ждать 50 мс?


Название: Re: read() Выход из чтения по таймеру
Отправлено: qate от Январь 27, 2015, 13:28

нужно блокировать. в этом фишка. иначе можно просто

while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ); лишняя нагрузка.


while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ) usleep(10000); // 10 мсек поспать всегда можно - нет тут нагрузки


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 13:29
нужно блокировать. в этом фишка. иначе можно просто

while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ); лишняя нагрузка.
Так пулинг и создан, что бы избавить нас от таких проверок и ненужных нагрузок.
Если данных для чтения не будет, то мы ничего делать и не будем.

что получается в вашем алгоритме: запустили таймер на 70 мс. запустили пулинг на 70мс. ждём.... через 50 мс получили кусок пакета... проверяем bytesAvailable() < 10 и запускаем следующий цикл пулинга... т.е. на 70 мс. больше байт допустим нет в пайпе. пулинг ждёт свои 70 мс. срабатывает таймер и вызывает onTimeout(). ...... вот тут как-то не всё элементарно.... что дальше? как onTimeout прервёт пулинг, которому ещё ждать 50 мс?
Как правило программа должна делать много разных вещей, по мимо сидения в select. Поэтому селект запускают с нулевым таймаутом (или очень маленьким), тогда он не ждет, а выходит сразу. Мы смотрим, есть что прочесть - читаем, потом мы делаем свои дела, например, смотрим на время (таймеры) и уходим в начало цикла на селект. И т.д.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 13:32

нужно блокировать. в этом фишка. иначе можно просто

while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ); лишняя нагрузка.


while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ) usleep(10000); // 10 мсек поспать всегда можно - нет тут нагрузки
не всегда можно. мне нужно ждать запрос. если запроса нет в течении 70 мс, то план Б.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 13:47
Так пулинг и создан, что бы избавить нас от таких проверок и ненужных нагрузок.
Если данных для чтения не будет, то мы ничего делать и не будем.
чего то я не пойму... вы то говорите что не нужно блокировать ожиданием.... то нужно блокировать пулингом ???


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

Код:
while( (timerIsOut() == false) || ( bytesAvailable() < 10 ) ); 

Мне же надо заблокироваться в ожидании до приема 10 байт, и прервать ожидание по таймауту, как это делается на примере read() с уртом.


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 14:37
Мне же надо заблокироваться в ожидании до приема 10 байт, и прервать ожидание по таймауту, как это делается на примере read() с уртом.
Я не могу понять для чего вы хотите именно заблокироваться в read?
Если можно не блокироваться и вычитывать по частям ваши 10 байт + контролировать время, для определения таймаута?
Вам шашечки или ехать?
И последовательный порт, и пайпы, и сокеты (локальные/сетевые) можно читать не блокируя, сколько нужно с контролем времени.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 15:06
Я не могу понять для чего вы хотите именно заблокироваться в read?
так вот с этого бы и начали, а потом бы уже предлагали неблокирующее чтение. Для чего мне нужно блокировать - это уже выходит за рамки этого топика.
Цитировать
Вам шашечки или ехать?
я сразу сказал, что мне нужно читать блокируя с контролем времени.


Название: Re: read() Выход из чтения по таймеру
Отправлено: xokc от Январь 27, 2015, 15:07
Я не могу понять для чего вы хотите именно заблокироваться в read?
...
И последовательный порт, и пайпы, и сокеты (локальные/сетевые) можно читать не блокируя, сколько нужно с контролем времени.
Предположу, что если речь идет о Windows и о пайпе, связанном с перенаправленным stdin, - будут проблемы с неблокируемым чтением. На эту тему тут на форуме несколько постов было.


Название: Re: read() Выход из чтения по таймеру
Отправлено: xokc от Январь 27, 2015, 15:13
я сразу сказал, что мне нужно читать блокируя с контролем времени.
Вижу два варианта - пользоваться системным API для имитации синхронного чтения через (Windows) ReadFile с Overlapped и WaitForSingleObject с 70 мс или читать в отдельном потоке, а по истечению 70 мс снаружи закрывать дескриптор читаемого файла - тогда "зависший" read вывалится с ошибкой.
Второй вариант выглядит значительно более корявым, но работает для того же чтения из stdin. Первый - по сути способ реализации того, что уже предлагал тут Old, но он Вам не нравится...


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 17:04
Предположу, что если речь идет о Windows и о пайпе, связанном с перенаправленным stdin, - будут проблемы с неблокируемым чтением. На эту тему тут на форуме несколько постов было.
сорри , сразу не сказал что речь про линукс. Но как увидел poll И select - сразу в маны. Это же библиотечные вызовы UNIX. Разве они в винде есть?


ps
Цитировать
по сути способ реализации того, что уже предлагал тут Old, но он Вам не нравится...
Да то, что Old предлагал, как-то.... эээ.... он предлагает не блокироваться в selecte. Кагбы уже я наверно всё выяснил... так ... мысли терзают... как можно вообще читать без блокировки? как можно писать алгоритмы подобные Old? это же равносильно коду
Цитировать
while(1);
Объясню почему:

Цитировать
while(!isTimerOut() ||(bytesAvailable < 10) )
{
select(...);
}
только не совсем понятно зачем здесь селект или полл нужен.
Такая нить грузит процессор на все 100%. Конечно планировщик этой нити не даст 100% процессора... но все ровно нехилую долю нить отъест. А если этих нитей будет 500 в программе? А если будет запущенно 500 экземпляров программы? То ваш какойнить ARM, на котором крутиться кинукс - ляжет. (Тем более, что изначально у меня по ТЗ было ожидание 450 мс. Сегодня 70 мс, завтра 2 сек сделают.) Правильно говорит gate, в таких случаях нужен sleep(), сним нагрузка будет пренебрежительно мала. Но писал бы я какой-нить терминал (типа HyperTerminal), или делал бы чтение датчика температуры - тут бы слып мне помог... тут можно было бы не на 10 мс уснуть, а на 1 сек. Но у меня другой случай.
Пример с уартом... в том же линуксе не зря придумали блокирующее чтение (хотя способом Old можно легко обойтись и без блокирующего чтения перегружая проц). Т.е. настроил таймауты, вызвал read, поток уснёт до прихода n байт и процессор не будет постоянно проверять получение байт, а будет заниматься другими задачами. Есть аналогичные API для винды.


Название: Re: read() Выход из чтения по таймеру
Отправлено: Old от Январь 27, 2015, 17:11
То что вы привели в качестве кода и близко не похоже на то, что пишет Old. :)
Вам стоит лучше разобраться в том, как организуется пулинг в подобном программном обеспечении и тогда вам сразу станет понятно, о чем я говорю.
А блокирующий read можно использовать в лабораторках или небольших утилитках.


Название: Re: read() Выход из чтения по таймеру
Отправлено: juvf от Январь 27, 2015, 17:31
То что вы привели в качестве кода и близко не похоже на то, что пишет Old. :)
Вам стоит лучше разобраться в том, как организуется пулинг в подобном программном обеспечении и тогда вам сразу станет понятно, о чем я говорю.
то что я привет в качестве кода 1в1 отражает ваш код.

Цитировать
А блокирующий read можно использовать в лабораторках или небольших утилитках.
ну ну... вот такие прогеры потом рождают  проги которые вешают компы.