while schleife unterbrechen



  • Hi,

    ich habe folgendes Problem:
    ich habe eine Endlosschleife in der ich etwas tun möchte, jetzt möchte ich, dass der Benutzer das jederzeit unterbrechen kann, aber die Endlosschleife läuft ohne auf den Input zu warten.

    while(1)
    {
    do something;
    if(getchar() == 'q')
    break;
    }
    

    wie kann ich das ohne Multithreading lösen?
    Viele Grüße



  • also unter windows gibts die möglichkeit über die conio.h zu gehen

    #include <conio.h>
    
    while ( true )
    {
        // machwas
        if ( _kbhit() )
            if ( _getch() == 'q' )
                break;
    }
    


  • ja das hab ich auch schon gefunden, aber das Problem ist dass das ganze unter Linux übersetzt werden muss 😞



  • das könnte dir helfen: http://www.linuxforums.org/forum/programming-scripting/109273-getch-doesn-t-work.html

    In kurz schau mal nach "tcsetattr()" .



  • helpMeplz schrieb:

    Hi,

    ich habe folgendes Problem:
    ich habe eine Endlosschleife in der ich etwas tun möchte, jetzt möchte ich, dass der Benutzer das jederzeit unterbrechen kann, aber die Endlosschleife läuft ohne auf den Input zu warten.

    while(1)
    {
    do something;
    if(getchar() == 'q')
    break;
    }
    

    wie kann ich das ohne Multithreading lösen?
    Viele Grüße

    Was soll das heißen, läuft ohne auf den Input zu warten?
    Entweder da ist noch was bei dir im Puffer, aber wenn kein q drin ist, sollte das auch kein Problem sein. Ansonsten musst du nach der Eingabe von q erstmal Enter drücken, denn sonst kann nichts ausgelesen werden. (das ist der Unterschied zu getch())



  • ich persönlich favorisiere:

    extern bool bDone;
    .
    .
    .
    int incrementor=0;
    while(!bDone)
    {
    // do something
        std::cout<<incrementor<<" loop\r\n";
    //check an additional condition
        if(incrementor>=my_finsih){ bDone=true;} else { incrementor++;}
    }
    

    break benutze ich nur für switch anweisungen um semantisch keinen fehler zu erzeugen und/oder einen zu übersehen,...

    greeetz



  • zeusosc schrieb:

    ich persönlich favorisiere:

    Das ist ja schrecklich!

    int incrementor=0;
    while(incrementor <= myFinish)
    	std::cout << incrementor++ << " loop\n";
    

    Meinetwegen fürs Inkrementieren auch ne neue Zeile, aber auf keinen Fall künstlich mit Bool-Variablen rumspringen, um nicht mal nötige breaks zu vermeiden.

    Selbst wenn break nötig wäre, wäre es immer noch deutlich schöner als dieses Sprachfeature 1:1 mit Bool-Variablen nachzubauen.



  • Was hast du denn für ein problem mit bool als conti oder break bedingung?



  • Weil es Speicher benötigt,
    weil es größeren unleserlicheren Code erzeugt,
    weil es einfach nicht notwendig ist.

    Sind wohl die schlagenden Argumente 😉



  • zeusosc schrieb:

    ich persönlich favorisiere:

    extern bool bDone;
    .
    .
    .
    int incrementor=0;
    while(!bDone)
    {
    // do something
        std::cout<<incrementor<<" loop\r\n";
    //check an additional condition
        if(incrementor>=my_finsih){ bDone=true;} else { incrementor++;}
    }
    

    ich versteh nicht ganz wie das mein Problem lösen kann? Wie bekomme ich denn da den User Input?



  • Ne,

    was ist mit einer multikonditionalen abbruchbedinung?
    was ist mit debugbarkeit?
    Kannst Du denn sagen welche der bedinungen erfüllt ist?
    Was ist mit wartbarkeit und übersichtlichkeit?
    Kannst du zusätzliche bedingungen einführen oder reduzieren ohne die übersichtlichkeit einzuschrenken?

    Nr1

    while(
          (i<size)
         &&
         ( 
          !(break_condition_1() || break_condition_2())
        ))
    {
    if(check_if_error()){ break;}
    ....
    }
    

    Nr2

    while(!bDone)
    {
    if(i>=size)
    { bDone=true;}
    
    if(break_condition_1())
    { bDone=true;}
    
    if(break_condition_2())
    { bDone=true;}
    
    if(check_if_error())
    { bDone=true;}
    
    };
    

    Nr2 ist übersichtlicher besser erweiterbar, wartbar und debugbar. Man sieht eindeutig welche kondition zutrifft in der ablaufverfolgung und "overhead" wird mit ner bool (ok, je nach system auch sizeof(int)) auch nicht produziert.

    Das einzige was zusätzlich kommt, ist die jeweilige zuweisung bDone=true, die konditionen werden so oder so überprüft (und aufgerufen), d.h. ich habe 3 zusätzliche asm zeilen gegenüber einer menge von vorteilen!

    Was meinst Du dazu?



  • zeusosc schrieb:

    was ist mit debugbarkeit?
    Kannst Du denn sagen welche der bedinungen erfüllt ist?

    Ja, man muss nur seinen Debugger bedienen können.

    Nr1

    while(
          (i<size)
         &&
         ( 
          !(break_condition_1() || break_condition_2())
        ))
    {
    if(check_if_error()){ break;}
    ....
    }
    

    Nr2

    while(!bDone)
    {
    if(i>=size)
    { bDone=true;}
    
    if(break_condition_1())
    { bDone=true;}
    
    if(break_condition_2())
    { bDone=true;}
    
    if(check_if_error())
    { bDone=true;}
    
    };
    

    Wenn man vier Bedingungen für ne while-Schleife hat und diese nicht sinnvoll in ne Funktion kapseln kann, macht man meiner Meinung nach was falsch. So ne Schleife muss mir erst mal gezeigt werden.
    Außerdem vermischst du hier zwei Punkte: Du musst mir noch erklären, warum

    while(!bDone)
    {
    if(i>=size)
    { bDone=true;}
    
    if(break_condition_1())
    { bDone=true;}
    
    if(break_condition_2())
    { bDone=true;}
    
    if(check_if_error())
    { bDone=true;}
    
    };
    

    übersichtlicher ist als

    while(i < size)
    {
        if(break_condition_1())
            break;
    
        if(break_condition_2())
            break;
    
        if(check_if_error())
            break;
    };
    


  • zu deiner letzten frage: ist es nicht,.. das sieht sauber aus und kann mit nem debugger gut nachvolzogen werden, da gebe ich Dir recht.

    zu deiner ersten:

    eine while loop in einem seperaten thread mit zusätzlicher extern setzbaren flag als abbruchbedingung und zig sonstige stati.

    Zum beispiel wenn eine Perepherie gesteuert werden muss, dann habe ich zig bedingungen die geprüft werden müsse, gleichzeitig muss aber sichergestellt werden dass diese extern abgebrochen werden kann.

    Nehme ich ein beispiel:
    Bleibe in der schleife
    solange: Laufzeit ( in s) nicht überschritten
    incrementor innerhalb eines spezifischen intervalls
    externes flag nicht gesetzt
    kein fehler auftritt
    tue: setze incrementor zur perepherie und prüfe den erfolg

    Dabei soll der wert des incrementor bei abbruch beibehalten werden, und die kopfgesteuerte schleifenbedingung zur laufzeit veränderbar sein.

    Wenn man vier Bedingungen für ne while-Schleife hat und diese nicht sinnvoll in ne Funktion kapseln kann, macht man meiner Meinung nach was falsch.

    Wie würdest Du das realisieren?
    (Ich lerne ja gerne dazu.. 😉 )

    Sei gegrüßt



  • Sieh es ein zeusosc, dein Ansatz ist hässlich, umständlich und nicht mal effizienter.



  • @helpMeplz:

    helpMeplz schrieb:

    zeusosc schrieb:

    ich persönlich favorisiere:

    extern bool bDone;
    .
    .
    .
    int incrementor=0;
    while(!bDone)
    {
    // do something
        std::cout<<incrementor<<" loop\r\n";
    //check an additional condition
        if(incrementor>=my_finsih){ bDone=true;} else { incrementor++;}
    }
    

    ich versteh nicht ganz wie das mein Problem lösen kann? Wie bekomme ich denn da den User Input?

    Unter "Do Something" ,... 🙂
    prinzipiell kann man da eine blockierende input fkt wie getch() nehmen, die wartet solange bis ein input kommt, ausser es soll solange etwas getan werden.

    Dann nehme ich (andere machens evtl. anders) einen seperaten thread, der entweder bDone setzt wenn ein input erfolgt ist und somit die while schleife beendet, oder man prüft innerhalb der while schleife ob der thread kompletiert ist. Dabei favoresiere ich aber Nr1 da dies eine geringere Laufzeit hat. Es wird ja immerhin auf eine "globale" variable geprüft. (ist aber nicht bedingt thread safe,..... hier geht es aber nur um ein beispiel),...

    greetz



  • anmerker schrieb:

    Sieh es ein zeusosc, dein Ansatz ist hässlich, umständlich und nicht mal effizienter.

    ?Das ist keine Antwort auf meine frage!
    Zeig mir bitte ein Code snippet unter genannten bedingungen der "nicht so hässlig und effizienter" ist. Wenn das gehtm so habe ich doch schon gesagt, nehme ich das gerne an. 😛



  • zeusosc schrieb:

    zu deiner letzten frage: ist es nicht,.. das sieht sauber aus und kann mit nem debugger gut nachvolzogen werden, da gebe ich Dir recht.

    Dann ist mein Hauptanliegen schon mal geklärt 😉

    Nehme ich ein beispiel:
    Bleibe in der schleife
    solange: Laufzeit ( in s) nicht überschritten
    incrementor innerhalb eines spezifischen intervalls
    externes flag nicht gesetzt
    kein fehler auftritt
    tue: setze incrementor zur perepherie und prüfe den erfolg

    Dabei soll der wert des incrementor bei abbruch beibehalten werden, und die kopfgesteuerte schleifenbedingung zur laufzeit veränderbar sein.

    Bei so allgemein gestellten Beispielen, ohne die Umstände zu kennen, finde ich es immer schwierig, eine gute Antwort zu geben, aber ich versuche es mal:
    Für den Abbruch von außen setze ich Interruption Points. Dass die Laufzeit nicht überschritten wird, kann man mit nem Timer sicherstellen, der sich auch in den Interruption Point einhängt. Die Bedingung, dass kein Fehler auftritt, löst man mit Exception Handling. Bleibt nur noch der Incrementor übrig. Also kommt etwa sowas raus:

    try
    {
    	while(incrementor < limit)
    	{
    		this_thread::interruption_point();
    		// was auch immer hier getan werden muss
    	}
    }
    catch(WhateverException& e)
    {
    }
    


  • hmm,.. sieht gut aus,..

    ich nutze aber kein boost, welche ja die interruption_point benutzt.

    D.h. ich nutze für einen "interrupt" einen multi-thread safe flag (also serialisierten) der ja prinzipiell das gleiche macht. (So verstehe ich dass jedenfalls.) Nach prüfung wird das done flag gesetzt und gemütlich aufgeräumt.

    Zu den Exceptionhandling, ich muss zugeben dass ich äusserst selten try catch throw blöcke nutze, ausser es sind system bezogene RunTime Error möglich. (Was meist eine quote bei mir weit unter 0,00002% beträgt, ausser ich habe mich dusselig angestellt.)

    Sachen wie memory überläufe, invalide memory zugriffe prüfe ich manuell innerhalb der methoden und mache sie auch manuell multi-Thread safe durch serialisierungscounter. Bei invalidität gebe ich dabei nicht á la throw einen fehler zurück sondern den fehler allgemein meist über den ret wert, oder als member variable der klasse wird der fehler gesetzt und danach/davor darauf geprüft. (Dabei handelt es sich meist auch um eine strucktur welche mehrere informationen über den fehler enthält)

    Über die Vor- nachteile beider möglichkeiten werde ich jetzt diskutieren wollen, aber in zukunft mal mehr damit beschäftigen.

    Seid gegrüßt und danke für die diskussion 😃



  • Da das ganze unter Linux laufen soll:

    #include <iostream>
    
    #include <errno.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>
    
    class terminal_rawifier {
    public:
      terminal_rawifier(int fd = STDIN_FILENO) : fd_(fd) {
        termios new_term_options;
    
        old_flags = fcntl(fd_, F_GETFL, 0);
        tcgetattr(fd_, &old_term_options);
    
        fcntl(fd_, F_SETFL, old_flags | O_NONBLOCK);
    
        new_term_options = old_term_options;
        new_term_options.c_lflag &= ~(ICANON | ECHO);
        tcsetattr(fd_, TCSANOW, &new_term_options);
      }
    
      ~terminal_rawifier() {
        tcsetattr(fd_, TCSANOW, &old_term_options);
        fcntl(fd_, F_SETFL, old_flags);
      }
    
    private:
      int old_flags;
      termios old_term_options;
      int fd_;
    };
    
    int main(void) {
      terminal_rawifier raw_term;
    
      while(1) {
        char c;
        ssize_t chars_read;
    
        std::cout << "foo" << std::endl;
    
        chars_read = read(STDIN_FILENO, &c, 1);
        if((chars_read == -1 && errno != EAGAIN) ||
           (chars_read ==  1 &&     c == 'q')) {
          break;
        }
      }
    }
    

    Das Gesumse mit read im C-Stil tut mir leid, aber ich glaube nicht, dass man std::cin in verlässlicher Weise die nötigen Statusinformationen entlocken kann.



  • zeusosc schrieb:

    Unter "Do Something" ,... 🙂
    prinzipiell kann man da eine blockierende input fkt wie getch() nehmen, die wartet solange bis ein input kommt, ausser es soll solange etwas getan werden.

    Dann nehme ich (andere machens evtl. anders) einen seperaten thread....

    Genau das ist das Problem, es soll etwas getan werden und nur einen Thread haben.
    Ich habe einfach keine Ahnung wie ich das lösen könnte.

    Grüße,


Anmelden zum Antworten