Как реализовать тайм-аут в вызове функции чтения?
Я хочу использовать последовательный COM-порт для связи, и я хочу реализовать тайм-аут каждый раз, когда я вызываю вызов функции чтения.
int filedesc = open( "dev/ttyS0", O_RDWR );
read( filedesc, buff, len );
EDIT:
Я использую ОС Linux. Как реализовать использование вызова функции select?
Ответы
Ответ 1
выберите()
принимает 5 параметров, сначала самый высокий файловый дескриптор + 1, затем fd_set для чтения, один для записи и один для исключений. Последний параметр - это struct timeval, используемый для тайм-аута. Он возвращает -1 по ошибке, 0 по таймауту или количеству дескрипторов файлов в наборах, которые установлены.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
int main(void)
{
fd_set set;
struct timeval timeout;
int rv;
char buff[100];
int len = 100;
int filedesc = open( "dev/ttyS0", O_RDWR );
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
rv = select(filedesc + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
printf("timeout"); /* a timeout occured */
else
read( filedesc, buff, len ); /* there was data to read */
}
Ответ 2
В качестве альтернативы select()
для конкретного случая последовательного порта (терминала) вы можете использовать tcsetattr()
, чтобы поместить дескриптор файла в неканонический режим с таймаутом чтения.
Чтобы сделать это, отмените флаг ICANON
и установите управляющий символ VTIME
:
struct termios termios;
tcgetattr(filedesc, &termios);
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */
tcsetattr(filedesc, TCSANOW, &termios);
Примечание VTIME
измеряется в десятых долях секунды, а тип, используемый для него, обычно равен unsigned char
, что означает, что максимальное время ожидания составляет 25,5 секунд.
Ответ 3
Если вы установили, что сокет работает в неблокирующем режиме, каждый вызов для чтения будет читать только имеющиеся данные (если есть). Таким образом, это фактически равно немедленному таймауту.
Вы можете установить неблокирующий режим в сокете с такой функцией:
int setnonblock(int sock) {
int flags;
flags = fcntl(sock, F_GETFL, 0);
if (-1 == flags)
return -1;
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
(Для получения дополнительной информации о чтении из неблокирующих сокетов см. справочную страницу read
)
Ответ 4
Вы не говорите, что такое ОС, но если вы работаете под Linux, вы можете использовать вызов select. Он возвращается, если есть что-то, что нужно прочитать в дескрипторе файла, или вы можете настроить его так, чтобы он перестал работать, если читать нечего. Код возврата указывает, какой.
Ответ 5
Приведенный ниже код использует миллисекундные таймауты на символ.
Я использую его в одном из моих проектов для чтения из COM-порта.
size_t TimeoutRead (int port, void*buf, size_t size, int mlsec_timeout)
{
struct pollfd fd = { .fd = port, .events = POLLIN };
size_t bytesread = 0;
while (poll (&fd, 1, mlsec_timeout) == 1)
{
int chunksize = read (port, buf + bytesread, size);
if (chunksize == -1)
return -1;
bytesread += chunksize;
size -= chunksize;
if (size == 0)
return bytesread;
}
// TODO: IsTimeout = true;
return bytesread;
}
Ответ 6
Linux рассматривает два типа устройств. "Медленно" (например, сеть) и "быстрый" (например, диск). Неблокирующий режим предназначен для "медленного" устройства, а не "быстрого". Блокируйте устройства, как предполагается, "быстрыми", поэтому select/poll всегда говорят, что они готовы к вводу/выводу. Для некоторых флеш-устройств это ложь, и я видел несколько вызовов ввода-вывода, которые используют несколько секунд для нескольких байтов, даже если select/poll сообщает, что устройство готово.
Это говорит, что даже для медленного устройства нет сильной гарантии на задержку чтения; Если вы предоставите буфер достаточно большой и данные доступны (вы использовали выбор или опрос, чтобы быть уверенным в этом), сам считываемый вызов может использовать значительное количество времени (сто мс в сети).