GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie führen Sie nicht blockierende Konsolen-E/A unter Linux in C durch?

Ich möchte ein Beispiel hinzufügen:

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

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

Wenn Sie dieses Programm ausführen, haben Sie 4 Sekunden Zeit, um Standardeingaben bereitzustellen. Wenn keine Eingaben gefunden werden, wird es nicht blockiert und einfach zurückgegeben.

2 Beispielausführungen:

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

Wie Pete Kirkham fand ich cc.byexamples.com, und es funktionierte für mich. Dort finden Sie eine gute Erklärung des Problems sowie die ncurses-Version.

Mein Code musste einen Anfangsbefehl von der Standardeingabe oder einer Datei übernehmen und dann auf einen Abbruchbefehl warten, während der Anfangsbefehl verarbeitet wurde. Mein Code ist C++, aber Sie sollten scanf() verwenden können und der Rest, wo ich die C++-Eingabefunktion getline() verwende .

Das Fleisch ist eine Funktion, die prüft, ob Eingaben verfügbar sind:

#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>

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

Dies muss vor jeder stdin-Eingabefunktion aufgerufen werden, wenn ich std::cin verwendet habe Vor der Verwendung dieser Funktion wurde nie wieder wahr zurückgegeben. Beispiel:main() hat eine Schleife, die so aussieht:

int main(int argc, char* argv[])
{ 
   std::string 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;
}

Im Eingabe-Thread wurden neue Befehle zu einer Warteschlange hinzugefügt, die periodisch von jobThread verarbeitet wurde . Die inputThread sah ungefähr so ​​aus:

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

Diese Funktion könnte wahrscheinlich in main() gewesen sein , aber ich arbeite mit einer bestehenden Codebasis, nicht dagegen.

Für mein System war keine Eingabe verfügbar, bis ein Zeilenumbruch gesendet wurde, was genau das war, was ich wollte. Wenn Sie jedes Zeichen bei der Eingabe lesen möchten, müssen Sie den "kanonischen Modus" auf stdin deaktivieren. cc.byexamples.com hat einige Vorschläge, die ich nicht ausprobiert habe, aber der Rest hat funktioniert, also sollte es funktionieren.


Linux
  1. E/A-Berichte über die Linux-Befehlszeile

  2. Wie stoppe ich einen „unterbrechungsfreien“ Prozess unter Linux?

  3. Ports für Linux und E/A-Abschluss?

  4. Wie erstellt man ein Fenster in Linux mit C++?

  5. Wie führe ich Low-Level-E/A für eine Linux-Gerätedatei in Python durch?

Wie viel Swap sollten Sie unter Linux verwenden?

So überprüfen Sie, ob Sie sich in einer Bildschirmsitzung befinden oder nicht in Linux

So sperren Sie virtuelle Konsolensitzungen unter Linux

So ändern Sie Schriftart und -größe der Linux-Konsole

So finden Sie heraus, welche Grafikkarte Sie unter Linux haben

Wie lösche ich Festplatten-E/A-Caches unter Linux?