Disposer d'un read non bloquant

Disposer d'un read non bloquant - C - Programmation

Marsh Posté le 31-12-2004 à 13:56:57    


Un problème récurrent évoqué sur le forum est le fameux read
bloquant, je vous propose d'y voir un peu plus clair.
 
Mettre un fd en mode non bloquant:

Code :
  1. #include <fcntl.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. int main()
  7. {
  8.         int     mode;
  9.         int     ret;
  10.         char    buf[512];
  11.         int     fd;
  12.         int     data = 1;
  13.         int     timeout = 3;
  14.         fd = 0;
  15.         mode = fcntl(fd, F_GETFL, 0);
  16.         mode |= O_NONBLOCK;
  17.         fcntl(fd, F_SETFL, mode);
  18.         while ( data ) {
  19.                 ret = read(0, buf, 512);
  20.                 switch (ret) {
  21.                         case -1:
  22.                                 if ( errno == EAGAIN ) {
  23.                                         printf("degoute, rien a lire, j'attends %d secondes\n", timeout);
  24.                                         sleep(timeout);
  25.                                         continue;
  26.                                 }
  27.                                 break;
  28.                         case 0:
  29.                                 data = 0;
  30.                                 break;
  31.                         default:
  32.   /* je ne mets pas de 0 terminal,
  33.    ** car je n'affiche que 'ret' caractères...  
  34.   */
  35.                                 printf(">> %.*s\n", ret, buf);
  36.                 }
  37.         }
  38.         return 1;
  39. }


 
Ce programme n'est pas capable d'executer quelquechose à l'instant
ou la donnée est disponible, il va forcément faire le
sleep(timeout) en entier.
 
Il faut utiliser select ou mieux poll pour sortir dès qu'une donnée
est disponible...

Code :
  1. int wait_for_input()
  2. {
  3.  int             ret = 0;
  4.  struct pollfd   fds;
  5.  /* on regarde sur l'entree standard */
  6.  fds.fd = 0;
  7.  fds.events = POLLIN;
  8.  if ( ! poll(&fds, 1, 5000) ) {
  9.   printf("rien à lire\n" );
  10.   /* ici ca fait 5 secondes que rien n'est
  11.   ** arrivé  
  12.   */
  13.  }
  14.  if ( fds.revents & ( POLLOUT | POLLERR | POLLHUP ) ) {
  15.   printf("Deconnexion ... fin de fichier\n" );
  16.   /* ici on sait que le read va retourner 0 */
  17.  }
  18.  if ( (ret = read( 0, buf, 512 )) < 0 ) {
  19.   printf("Probleme de lecture..." );
  20.   /* ici le read à foiré */
  21.  }
  22.  /* ici 'buf' est rempli de 'ret' caractères */
  23. }


 
 
 
Cadeau bonus, Spécial flex....

Code :
  1. %{
  2. #include <poll.h>
  3. /* variable externe utilisée dans une boucle quelconque permettant
  4. * d'arreter le déroulement du programme...
  5. *
  6. extern int  fatal;
  7. static void             fatal_error(const char *msg);
  8. #define YY_FATAL_ERROR(msg) fatal_error(msg);
  9. /* timeout de 5 secondes */
  10. #define YY_INPUT(buf, result, max_size) \
  11.         do { \
  12.                 int             ret = 0; \
  13.                 struct pollfd   fds; \
  14.                 fds.fd = 0; \
  15.                 fds.events = POLLIN; \
  16.                 if ( ! poll(&fds, 1, 5000) ) { \
  17.                         fatal = 1; \
  18.                         result = 0; \
  19.                         YY_FATAL_ERROR("input in flex scanner failed timeout reading" ) \
  20.                         goto skip_reading; \
  21.                 } \
  22.                 if ( fds.revents & ( POLLOUT | POLLERR | POLLHUP ) ) { \
  23.                         fatal = 1; \
  24.                         result = 0; \
  25.                         goto skip_reading; \
  26.                 } \
  27.                 if ( (result = read( 0, (char *) buf, max_size )) < 0 ) { \
  28.                         YY_FATAL_ERROR( "input in flex scanner failed" ) \
  29.                 } \
  30. skip_reading: \
  31.         } while (0)
  32. %}
  33. %%
  34. %%
  35. static void fatal_error(const char *msg)
  36. {
  37.         printf("fatal error: %s\n", msg);
  38. fatal = 1;
  39. }

Reply

Marsh Posté le 31-12-2004 à 13:56:57   

Reply

Marsh Posté le 13-03-2010 à 15:55:51    

Merci, votre code m'a avancé en ce qui concerne la création d'un getch() sous Linux. En revanche, j'essaie également de créer ma propre fonction au comportement similaire à getch() sous Windows, dans un but d'acquérir un contrôle accru sur l'entrée clavier. Select, poll, passer en mode non canonique avec fcntl, tout ça m'est refusé sous Windows. Je cherche non-stop depuis hier soir, auriez-vous une idée?

Reply

Marsh Posté le 02-04-2010 à 00:07:22    

Je sais que tu peux indiquer a un file-descriptor d'etre bloquand ou non via tcgetattr(fd, struct termios *w);
tu modifies les valeurs de ta structure termios:

Code :
  1. #include <termios.h>
  2.   struct termios  w;
  3.   tcgetattr(0, &w);
  4.   w.c_cc[VMIN] = 0;
  5.   w.c_cc[VTIME] = 0;
  6.   w.c_lflag &= ~(ICANON);
  7.   tcgetattr(0, TCSANOW, &w);


 
ce code fonctionne sous FreeBSD. ça pourrai peut être fonctionner sous un Linux mais dodows c'est mort

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed