2016-05-24 3 views
0

Ich habe noch keinen Post gefunden, der ein ähnliches Szenario behandelt:
In einem Kommandozeilen-Unix-Programm für die Sonifikation bestimmter Gleitkommadatensätze, Ich habe eine main(), die entweder liest aus einer Datei, deren Name als Programm argumant oder stdin Umleitung (<) oder Daten aus einem anderen Programm (|), abhängig von argc. Solange argv[1] ein Dateiname ist, kann ich die Ausführung sanft stoppen, indem ich die Eingabetaste drücke, die programmatisch eine Bedingung zum Ausblenden des Signals einstellt, die Audiounterroutine aufreinigt und regelmäßig beendet und das Programm beendet. Ich erreiche es durch Aufruf einer Funktion für nicht blockierende kbhit(). Definition:Stoppen eines Unix-Programms mit der Tastatur, während der umgeleiteten Eingabe, ohne SIGINT, in C

int kbhit(void) 
{  
    struct timeval tv; 
    fd_set read_fd; 

    tv.tv_sec = 0; 
    tv.tv_usec= 0; 

    FD_ZERO(&read_fd);  
    FD_SET(0, &read_fd); 

    if(select(1, &read_fd, NULL, NULL, &tv) == -1) 
     return 0; 

    if(FD_ISSET(0, &read_fd)) 
     return 1; 

    return 0;  
} 

Wenn jedoch Eingang umgeleitet oder geleitet wird, verhindert kbhit() dann von der Ausführung durch die Wiedergabe in dem Moment gestoppt es begonnen hat, da es 1 zurückgibt. Ich weiß nicht, wie ich damit umgehen soll, deshalb verwende ich SIGINT, was ich nicht so elegant finde. Hier ist der Code-Schnipsel:

//... ... 
bool stop = false;  //global variable 
//... ... 
if(argc == 1) stdr = true;//flag: reading from redirected or piped stdin (simplified) 

//code for reading from file or stdin, using fscanf() ... 
//code for initializing and starting audio process ... 
//loop, during audio callback on a separate thread ... 
while((player.totalFrames < player.totalSize) && !stop){ 
    if(!stdr){  //(= reading from file) 
     if (kbhit()){ 
     stop = true; 
     break; 
     } 
    }else{   //(= reading from redirected stdin) 
     if (signal(SIGINT, sig_handler) == SIG_ERR) 
     printf("\ncan't catch SIGINT\n"); 
    }   
} 

if(stop){ … }//code for gently fading the signal and stopping the audio process 
//cleanup and termination... 
//... ... 

Und hier ist die Standard-Signal-Handler, die stop setzt Bedingung true:

void sig_handler(int s) 
{ 
    if (s == SIGINT){ 
     if(debug)printf("\ncaught SIGINT\n"); 
     stop = true; 
    } 
} 

Gibt es eine elegantere Möglichkeit zu:

  1. senden & eine Nachricht von der Tastatur abfangen, während die Eingabe umgeleitet oder piped ist, um eine Programmbereinigung nach sich selbst zu ermöglichen und zu beenden (anders als mit SIGINT wie beschrieben) über)?
  2. Wie sieht ein Code aus, der eine solche Meldung von Coputer KeyOard (während Umleitung oder Verrohrung) zulässt? Könnten die Argumente innerhalb von kbhit() irgendwie neu arrangiert werden, oder man muss in eine völlig andere Richtung gehen. Ich habe keine Ahnung welche?

    Wenn das möglich ist, würde ich mich über einen Vorschlag freuen. Danke im Voraus!

+0

Warum möchten Sie SIGINT nicht verwenden? Genau dafür ist es da. – Gilles

+0

Wie Sie im Beispielcode sehen können, verwende ich ** SIGINT und es funktioniert. Ich schaue nur, ob es etwas Eleganteres gibt. – user3078414

+0

Hinweis: Verwenden Sie keine booleschen Typen und Konstanten von Homebrew. C hat einen Standard-boolena-Typ und 'stdbool.h' definiert die Konstanten auch als Makros. Benutze es! – Olaf

Antwort

1

Wenn Sie ein interaktiver TTY Benutzer in der Lage sein, ein Programm mit einem Eingabezeichen zu stoppen (keine Signalisierungs Charakter, der die TTY-Treiber verursacht ein Signal zu liefern), und das Programm muss umgeleitet werden, dann Nur ein Ausweg ist das explizite Öffnen eines Dateideskriptors für das TTY-Gerät (über /dev/tty) und das Überwachen dieses für die Eingabe.

Ihre kbhit Funktion sollte wahrscheinlich einen int fd Parameter nehmen, mit dem Sie es den offenen TTY-Dateideskriptor geben, den es abfragen sollte.

Wenn eine einzelne Zeicheneingabe von einem TTY sofort für das Programm verfügbar sein soll (auch wenn dieses Zeichen kein Zeilenumbruch ist), müssen Sie das TTY in den "Rohmodus" oder zumindest teilweise versetzen Zumindest müssen Sie die "kanonische Eingabeverarbeitung" deaktivieren, indem Sie das ICANON Flag im c_iflag numerischen Feld in der struct termios Struktur negieren und sicherstellen, dass c_cc[VTIME] und c_cc[VMIN] auf 0 bzw. 1 gesetzt sind. Nachschlagen tcgetattr und tcsetattr. Wahrscheinlich möchten Sie die Signalisierungszeichen deaktivieren und das Echo und andere Dinge deaktivieren.Einige Plattformen haben eine cfmakeraw Funktion, die ein struct termios Objekt in den richtigen Weisen zwickt, um einen sehr rohen Modus zu verursachen, ohne mit irgendwelchen der termios Flaggen herumspielen zu müssen.

Im kanonischen Eingabeverarbeitungsmodus stellt ein TTY dem Prozess keine Eingabe zur Verfügung (und wählt nicht positiv für die Eingabe unter select), bis eine vollständige Zeile der Eingabe empfangen wird.

+0

Es ist sehr wahrscheinlich, dass ich in dieser Richtung weitermachen muss. Kennen Sie einen Beispielcode, den ich studieren könnte? Danke vielmals! – user3078414

+0

Die folgende Frage wurde auf [Unix-Stapelaustausch] gefunden (http://unix.stackexchange.com/questions/25291/writing-to-stdout-except-for-output-redirection-c). Da eine der Antworten ein nettes, minimales, funktionierendes ** C ** Code ** Beispiel enthält, poste ich den Link hier. – user3078414

1

Ihr Problem ist, dass Sie beim Lesen von Daten aus der Umleitung versuchen, sowohl die Datei UND Ihre Tastatur zu verwenden. stdin ist nicht mehr Ihre Tastatur, es ist die Datei und somit können Sie keine Daten von Ihrer Tastatur lesen (wie die "enter" Taste gedrückt).

Wenn ich mich nicht irre, sind Ihre einzigen zwei Optionen Signale und Öffnen eines neuen Dateideskriptors für die Tastatureingabe (TTY).

+0

Nein, ich versuche nicht, die Datei zu verwenden, wenn ich aus der Umleitung lese - das ist klar aus dem Code. Ich benutze bereits Signale. Wahrscheinlich würde ich einen neuen Dateideskriptor öffnen. Danke für deinen Beitrag. – user3078414

Verwandte Themen