Comment gérez-vous les E / S de console non bloquantes sous Linux en C?

Comment faites-vous pour la console non-bloquante IO sous Linux / OS X en C?

    Vous ne le faites pas vraiment. Le TTY (console) est un périphérique assez limité, et vous ne faites pratiquement pas d’E / S non bloquantes. Ce que vous faites lorsque vous voyez quelque chose qui ressemble à des E / S non bloquantes, par exemple dans une application curses / ncurses, est appelé E / S brutes . Dans les E / S brutes, il n’y a pas d’interprétation des caractères, pas de traitement d’effacement, etc. Au lieu de cela, vous devez écrire votre propre code qui vérifie les données tout en faisant d’autres choses.

    Dans les programmes C modernes, vous pouvez simplifier cela en plaçant les E / S de la console dans un processus thread ou léger. Ensuite, les E / S peuvent continuer à se bloquer normalement, mais les données peuvent être insérées dans une queue pour être traitées sur un autre thread.

    Mettre à jour

    Voici un tutoriel sur les malédictions qui le couvre plus.

    Comme Pete Kirkham , j’ai trouvé cc.byexamples.com , et cela a fonctionné pour moi. Allez-y pour une bonne explication du problème, ainsi que la version ncurses.

    Mon code devait prendre une commande initiale à partir d’une entrée standard ou d’un fichier, puis rechercher une commande d’annulation pendant le traitement de la commande initiale. Mon code est C ++, mais vous devriez pouvoir utiliser scanf () et le rest où j’utilise la fonction d’entrée C ++ getline ().

    La viande est une fonction qui vérifie s’il y a des entrées disponibles:

     #include  #include  #include  // cc.byexamples.com calls this int kbhit(), to mirror the Windows console // function of the same name. Otherwise, the code is the same. bool inputAvailable() { struct timeval tv; fd_set fds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); return (FD_ISSET(0, &fds)); } 

    Ceci doit être appelé avant toute fonction d’entrée stdin. Quand j’ai utilisé std :: cin avant d’utiliser cette fonction, elle n’est jamais revenue à nouveau. Par exemple, main () a une boucle qui ressemble à ceci:

     int main(int argc, char* argv[]) { std::ssortingng initialCommand; if (argc > 1) { // Code to get the initial command from a file } else { while (!inputAvailable()) { std::cout << "Waiting for input (Ctrl-C to cancel)..." << std::endl; sleep(1); } std::getline(std::cin, initialCommand); } // Start a thread class instance 'jobThread' to run the command // Start a thread class instance 'inputThread' to look for further commands return 0; } 

    Dans le thread d'entrée, de nouvelles commandes ont été ajoutées à une queue, qui était traitée périodiquement par le jobThread. Le inputThread ressemblait un peu à ceci:

     THREAD_RETURN inputThread() { while( !cancelled() ) { if (inputAvailable()) { std::ssortingng nextCommand; getline(std::cin, nextCommand); commandQueue.lock(); commandQueue.add(nextCommand); commandQueue.unlock(); } else { sleep(1); } } return 0; } 

    Cette fonction aurait probablement pu être dans main (), mais je travaille avec une base de code existante, pas contre elle.

    Pour mon système, aucune entrée n'était disponible avant l'envoi d'une nouvelle ligne, ce qui était exactement ce que je voulais. Si vous voulez lire chaque caractère saisi, vous devez désactiver le "mode canonique" sur stdin. cc.byexamples.com a quelques suggestions que je n'ai pas essayées, mais le rest a fonctionné, alors ça devrait marcher.

    Je veux append un exemple:

     #include  #include  #include  int main(int argc, char const *argv[]) { char buf[20]; fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK); sleep(4); int numRead = read(0,buf,4); if(numRead > 0){ printf("You said: %s", buf); } } 

    Lorsque vous exécutez ce programme, vous disposez de 4 secondes pour fournir une entrée standard. Si aucune entrée n’est trouvée, cela ne bloquera pas et reviendra simplement.

    2 exemples d’exécution:

     Korays-MacBook-Pro:~ koraytugay$ ./a.out fda You said: fda Korays-MacBook-Pro:~ koraytugay$ ./a.out Korays-MacBook-Pro:~ koraytugay$ 

    J’ai mis en signet ” Entrée utilisateur non bloquante en boucle sans ncurses ” plus tôt ce mois-ci quand je pensais avoir besoin d’une entrée de console non bloquante et non tamponnée, mais je ne l’ai pas fait. Pour mon usage, je ne me suis pas soucié du fait qu’il n’a pas été saisi tant que l’utilisateur n’a pas appuyé sur enter, donc il a juste utilisé aio pour lire stdin.

    Voici une question connexe à l’aide de C ++ – C ++ IO non bloquant multiplate-forme (linux / Win32) sur stdin / stdout / stderr

    utiliser ncurses

    Une autre alternative à l’utilisation de ncurses ou de threads consiste à utiliser GNU Readline , en particulier la partie qui vous permet d’ enregistrer des fonctions de rappel . Le patron est alors:

    1. Utilisez select () sur STDIN (parmi d’autres descripteurs)
    2. Lorsque select () vous indique que STDIN est prêt à être lu, appelez read_rall_callback_read_char ()
    3. Si l’utilisateur a saisi une ligne complète, rl_callback_read_char appellera votre rappel. Sinon, il retournera immédiatement et votre autre code pourra continuer.

    Vous n’êtes pas tout à fait sûr de ce que vous entendez par «console IO» – lisez-vous STDIN, ou s’agit-il d’une application console qui lit à partir d’une autre source?

    Si vous lisez STDIN, vous devez ignorer fread () et utiliser read () et write (), avec poll () ou select () pour bloquer les appels. Vous pourrez peut-être désactiver la mise en mémoire tampon des entrées, ce qui entraînera le retour du fread pour un EOF, avec setbuf (), mais je ne l’ai jamais essayé.