Warten bis Bedingung eintrifft



  • Hey.

    Ich habe eine Problem.

    Ich suche eine Methode oder so, die wartet bis eine Bedingung erfüllt ist, aber nicht den Mainthread blockiert, womit while(...){..} schonmal weg fällt. Gibt es sowas?? Hatte mir sowas wie:

    WaitFor(a == b);
    // oder
    WaitFor(a, b);
    

    vorgestellt.

    Das ganze hat den Sinn, dass eine Methode wartet, bis ein Ereignis den Wert entsprechend setzt und dann fortfährt. Mit while(...) blockiert man ja aber den athread und somit jegliche Nutzereingaben und entsprechende Events.



  • Die Monitor-Klasse könnte interessant für Dich sein, insbesondere die Methoden:
    Monitor.Wait
    Monitor.Pulse

    oder die Klassen:
    AutoResetEvent
    ManualResetEvent



  • Du kannst auch den BackgroundWorker dafür einsetzen.



  • Das Pendant in anderen Sprachen ist eine Condition Variable.



  • Okey..
    Erstmal Danke für die Antworten. - Stehe grade aber etwas auf der Leitung 😞

    Wie soll ich mit der Monitor.Wait() Methode umgehen.. Was für ein Objekt soll ich da setzen??

    Und wie stellst du dir das mit einem BG-Worker vor.. Iwie krieg ichs nicht hin.

    Habt ihr vielleicht mal ein kurzes Code-Beispiel?? Thx.



  • Ich hoffe der Code ist ohne Kommentare selbsterklärend:

    var worker = new BackgroundWorker();
    
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync();
    ...
    
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
       while (<Condition>)    
       { }
    }
    
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      MessageBox.Show("Done.);
    }
    


  • #Darius# schrieb:

    Wie soll ich mit der Monitor.Wait() Methode umgehen.. Was für ein Objekt soll ich da setzen??

    Lies ein Tutorial über Threading.
    http://www.albahari.com/threading/



  • #Darius# schrieb:

    Das ganze hat den Sinn, dass eine Methode wartet, bis ein Ereignis den Wert entsprechend setzt und dann fortfährt. Mit while(...) blockiert man ja aber den athread und somit jegliche Nutzereingaben und entsprechende Events.

    Wie stellst du dir das vor?
    Wie soll das gehen, nicht blockierenderweise zu warten, aber trotzdem die Methode nicht zu verlassen?



  • hustbaer schrieb:

    #Darius# schrieb:

    Das ganze hat den Sinn, dass eine Methode wartet, bis ein Ereignis den Wert entsprechend setzt und dann fortfährt. Mit while(...) blockiert man ja aber den athread und somit jegliche Nutzereingaben und entsprechende Events.

    Wie stellst du dir das vor?
    Wie soll das gehen, nicht blockierenderweise zu warten, aber trotzdem die Methode nicht zu verlassen?

    Mit await und async 😉



  • @Firefighter
    Darum geht's nicht.

    Es geht darum dass #Darius# keine Vorstellung davon hat wie ein Programm abläuft. Ich denke es wäre wichtig für ihn zu verstehen warum das so wie er es sich vorstellt nicht gehen kann.
    Und wie man den selben Effekt anders erreichen kann.

    await/async ist ein Feature das man definitiv nicht verwenden sollte, wenn man nicht verstanden hat was im Hintergrund abgeht.



  • Naja.. hustbaer hat garnicht so unrecht damit, dass es nicht soeinfach ist.

    Das mit dem BackgroundWorker oder ähnlichem funktioniert deshalb nicht, da ich einen Rückgabewert brauche.

    public string Read()
    {
      # Vorbereitung #
      # Solange warten, bis die Bedigung auf Grund der Auslösung eines Anderen Events erfüllt ist und damit auch der Rückgabewert(-> Wird von anderen Event-Gesteuerten Methoden angepasst) der gewollte ist. #
      return #rückgabewert#;
    }
    

    ^^ Wie sollte ich das mit dem BG-Worker machen??

    Entschuldigung, wenn ich mich schlecht ausgedrückt hatte 😉

    Also..?? Keine anderen Möglichkeiten, mit denen ich direkt in der Methode bleibe??



  • hustbaer schrieb:

    @Firefighter
    Darum geht's nicht.

    Es geht darum dass #Darius# keine Vorstellung davon hat wie ein Programm abläuft. Ich denke es wäre wichtig für ihn zu verstehen warum das so wie er es sich vorstellt nicht gehen kann.
    Und wie man den selben Effekt anders erreichen kann.

    await/async ist ein Feature das man definitiv nicht verwenden sollte, wenn man nicht verstanden hat was im Hintergrund abgeht.

    Recht hat er.



  • Prüf doch einfach da wo die Daten, auf die gewartet wird, erzeugt werden obs weiter gehen kann?



  • @#Darius#
    Kurzfassung: es gibt Hacks mit denen man das machen kann (in den meisten Fällen, auch nicht in allen), aber ich würde die keinem empfehlen.

    Saubere Lösungen gibt es mehrere:

    1. Alles auf asynchron umbauen. Dann hast du ein BeginRead() statt Read(), und BeginRead() kann sofort zurückkehren. Das "zu Fuss" zu machen ist reichlich aufwendig, und auch nicht ganz einfach fehlerfrei hinzubekommen.
      Vor allem ist ja bei Read() nicht Schluss.
      Die Funktion die Read() aufruft wartet ja auf das Ergebnis. Also muss die auch asynchron werden. Und das kann sich dann beliebig viele Ebenen nach oben weiterziehen.

    Andrerseits würde dir das zu einem Verständnis verhelfen wie man sowas macht. Und wenn du das weisst, dann guckst du dir async/await an. Mit dem kannst du beim nächsten Mal dann das selbe mit viel weniger Code/Aufwand machen.

    1. Du lässt die eigentlichen "Arbeiter-Funktionen" blockierend, und lagerst den ganzen Vorgang in einen Worker-Thread aus. Also nicht die Read Funktion, sondern den ganzen Vorgang der diese Read Funktion benötigt.

    Um dir hier konkrete Vorschläge zu bringen müsste man allerdings wissen was du da eigentlich programmierst. Also was ist das was nicht blockiert werden soll (Forms GUI? WPF GUI? Eigene Screen-Update-Schleife eines Spiels? ...?). Und was ist der blockierende Vorgang der nicht mehr blockieren soll. Also nicht das Read, sondern der Vorgang der diese Read-Funktion braucht.



  • Erstmal Danke für die Erklärung. Ich schau mich mal etwas genauer um auf dem Gebiet.

    Die Methode selbst ist in einer Klasse, die man über Konsole oder irgendwas anderes aufrufen kann. Im Endeffekt aber Forms. Also die Klasse erstellt mit jeder neuen Instanz ein neues Formular und zeigt dieses an.

    Das kann man dann "Steuern" mit Befehlen über die Hauptanwendung.
    Das dargestellte Fenster ist eine Art Konsole.

    Der Read Befehl setzt eine Variable auf true die angibt ob Tastatureingaben entgegengenommen werden sollen. Eine weitere Variable gibt an ob der Nutzer die Eingabe bestätigt hat. Die Eingabevariable soll dann durch Events befüllt werden und bei Enter wird die oben genannte Variable auf true gesetzt. Dann soll die Readmethode den Wert zurückgeben. Allerdings darf der Inhalt der Readmethode ja nicht den Thread und damtit die Nutzereingaben-Events blockieren.

    Hoffe ich habe mich verständlich ausgedrückt.



  • #Darius# schrieb:

    Hoffe ich habe mich verständlich ausgedrückt.

    Nein, nicht sehr.

    Wie wär's wenn du beschreibst was das Ding tun soll, anstatt wie du versucht hast es zu implementieren?

    Ansonsten...
    Klingt so als liesse sich das relativ einfach lösen, indem jede "Konsole" ihren eigenen GUI-Thread startet, mit dem "ihr" Fenster bedient wird. Dann kann der "Read-ausführende" Thread ruhig blockieren während darauf gewartet wird dass ne Eingebe kömmt.
    FALLS ich richtig verstanden habe was du erreichen willst.



  • Das "Ding" soll arbeiten wie eine "erweiterte" Konsole.
    Man kann Informationen ausgeben oder einlesen.
    Beim Einlesen wird darauf gewartet, dass der Rückgabestring von Event-Getsteuerten Methoden gefüllt wird und bei einem bestimmten Event der string zurückgegeben wird.



  • Ich weiss nicht was daran "erweitert" sein soll, aber das schreit ja gerade nach einem eigenen Thread.



  • Es tut mir wirklich leid, wenn ich euch jetzt hier belästige, aber ich stehe grade extremst auf dem Schlauch. Welchen Part soll ich auslagern. Wie mache ich das mit dem Rückgabewert bzw. return.. ?


Anmelden zum Antworten