Подтвердить что ты не робот

Как реализовать тайм-аут в вызове функции чтения?

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

int filedesc = open( "dev/ttyS0", O_RDWR );

read( filedesc, buff, len );

EDIT:

Я использую ОС Linux. Как реализовать использование вызова функции select?

4b9b3361

Ответ 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 сообщает, что устройство готово. Это говорит, что даже для медленного устройства нет сильной гарантии на задержку чтения; Если вы предоставите буфер достаточно большой и данные доступны (вы использовали выбор или опрос, чтобы быть уверенным в этом), сам считываемый вызов может использовать значительное количество времени (сто мс в сети).