web-dev-qa-db-fra.com

Comment implémenter un timeout dans l'appel de fonction de lecture?

Je souhaite utiliser le port série COM pour la communication et je veux implémenter un délai d'expiration chaque fois que j'appelle l'appel de fonction de lecture.

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

read( filedesc, buff, len );

MODIFIER:

J'utilise Linux OS. Comment mettre en œuvre en utilisant l'appel de fonction de sélection?

47
domlao

select () prend 5 paramètres, d'abord le descripteur de fichier le plus élevé + 1, puis un fd_set pour la lecture, un pour l'écriture et un pour les exceptions. Le dernier paramètre est une structure temporelle, utilisée pour le timeout. Il renvoie -1 en cas d'erreur, 0 en cas de dépassement de délai ou le nombre de descripteurs de fichier dans les ensembles définis.

#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 */
}
76
Puppe

Comme alternative à select(), pour le cas spécifique d'un port série (terminal), vous pouvez utiliser tcsetattr() pour mettre le descripteur de fichier en mode non canonique, avec un délai de lecture.

Pour ce faire, désactivez l'indicateur ICANON et définissez le caractère de contrôle 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);

Remarque VTIME est mesuré en dixièmes de seconde et que le type utilisé est généralement un unsigned char, ce qui signifie que le délai maximal est de 25,5 secondes.

39
caf

Si vous définissez le socket fonctionne en mode non bloquant, chaque appel à lire lira uniquement les données actuellement disponibles (le cas échéant). Donc, cela équivaut effectivement à un délai d'attente immédiat.

Vous pouvez définir le mode non bloquant sur un socket avec une fonction comme celle-ci:

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);
}

(Pour plus d'informations sur la lecture à partir de sockets non bloquants, consultez la page de manuel read)

8
sth

Vous ne dites pas ce qu'est le système d'exploitation, mais si vous exécutez sous Linux, vous pouvez utiliser l'appel de sélection. Il retourne s'il y a quelque chose à lire sur le descripteur de fichier ou vous pouvez le configurer pour qu'il expire s'il n'y a rien à lire. Le code retour indique lequel.

4
sizzzzlerz

Le code ci-dessous utilise des délais d'attente en millisecondes par caractère. Je l'utilise dans l'un de mes projets pour lire depuis le port 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;
}
0
rick-rick-rick