Arbeiten mit Events.



  • Frolo schrieb:

    Okay, hab mir das von @krümelkacker angeschaut (noch nicht getestet). Ich habe generell ja bis jetzt nur mit den Delphi Events gearbeitet, aber nach gründlichem Nachdenken, bin ich darauf gekommen, dass Events in Delphi doch synchron sind.

    Du sagst "Events" meinst aber was anderes: Delegates. Über Delegates werden Handler festgelegt, die von einem Event-Loop aus aufgerufen werden.

    Frolo schrieb:

    Wenn ich ne while(1)-Schleife in ein Delphiprogramm schreibe und beispielsweise in ein ButtonClick Event schreibe, hängt sich das Programm (die GUI) auf. Deshalb denke ich, dass das ganze synchron ist.

    Du schreibst kein "Event". Du schreibst einen Handler, einen Handler der vom Event-Loop aus aufgerufen wird. Wenn der Handler dann eine Endlosschleife enthält und nicht zum Event-Loop zurückkehrt, dann kann das Program nicht mehr auf weitere Events reagieren. Um die GUI "ansprechbar" zu halten, müssen Handler also schnell abgearbeitet werden.

    Frolo schrieb:

    Jetzt nochmal zu meiner Frage: Ist es durch den Vorschlag von "krümelkacker" möglich so etwas ähnliches zu machen:

    Du wolltest wissen, wie man delegates in C++ bekommen würde, wobei du statt "delegates" eben "events" gesagt hast. Dazu hatte ich ein Beispiel. Ein Event-Loop ist u.a. irgendwo in QT implementiert. Sowas kann man sich selbst bauen. Muss man möglicherweise aber nicht. Da hört dann auch meine Expertise auf.

    Frolo schrieb:

    //PSEUDO-CODE
    MeinTCPClient tcp1;
    
    //-------------
    
    void MeineProc {
     //die soll aufgerufen werden, wenn ein neuer Client connected
    }
    
    tcp1.OnConnect = MeineProc;
    

    So würde ich mir das im Prinzip wünschen, dass es später eben genau so einfach ist. Kann ich das so machen (oder ähnlich) und wie müsste ich das dann innerhalb des Objekts umsetzen?

    Dann brauchst du einen Event-Loop, der mit einer Message-Queue arbeitet, wo man solche Events reinstecken kann.

    knivil schrieb:

    Was ist an boost::asio eigentlich Overkill in Bezug auf COM-Ports?

    Weil man sich die Abhaengigkeit zu boost hereinholt, obwohl man das Beispiel aus der MSDN fuer Comports quasi abschreiben kann.

    Verlink das doch mal. Ich hatte anfang dieses Jahres da nur mal mit einer "blocking API" gearbeitet. Und das war ein recht simples C-Interface, wo ich erstmal einen C++-Wrapper für RAII drumherum gebaut habe. Das ganze dann noch verPIMPLt, so das im Header nix System-spezifisches mehr steht.



  • http://msdn.microsoft.com/en-us/library/ff802693.aspx war meine Basis fuer meine eigene Comport-Klasse. Nun einfach sieht anders aus, aber was solls ... Das Hauptproblem bei overlapped IO ist, dass ich benachrichtigt werde, wenn meine Operation abgeschlossen ist. Es ist schwierig, eine gestartete Operation korrekt abzubrechen. Das Konzept unter Unix ist, ich werde benachrichtig wenn etwas verfuegbar ist. Das Problem des Abbrechens gibt es dort nicht.



  • Ich finde die Unterteilung synchron vs. asynchron sinnlos.
    Event-Callbacks werden immer synchron aufgerufen, die Frage ist nur synchron mit was.
    Das muss man halt wissen, und dann kann man das Programm entsprechend darauf auslegen.

    Falls man sich nicht mit Multithreading auskennt, dann wäre es natürlich vorteilhaft wenn es nur einen Thread gibt, und von diesem auch die Event-Callbacks ausgeführt werden.



  • knivil schrieb:

    http://msdn.microsoft.com/en-us/library/ff802693.aspx war meine Basis fuer meine eigene Comport-Klasse. Nun einfach sieht anders aus, aber was solls ... Das Hauptproblem bei overlapped IO ist, dass ich benachrichtigt werde, wenn meine Operation abgeschlossen ist. Es ist schwierig, eine gestartete Operation korrekt abzubrechen. Das Konzept unter Unix ist, ich werde benachrichtig wenn etwas verfuegbar ist. Das Problem des Abbrechens gibt es dort nicht.

    Habe jetzt nicht auf den Link geklickt, aber ich frage mich gerade, wo der Unterschied zwischen Windows und Unix Deiner Beschreibung nach sein soll. die erklärung ist nämlich fast gleich, bis auf dass du einmal "wenn die Operation abgeschlossen ist" und das andere mal "wenn etas verfügbar ist" sagst. Meinst du bei "etwas" hier _irgend_ etwas? Also eine Queue, wo alle Events reinkommen statt eines Callback-Mechanismus bei Windows?



  • Er meint reactive IO vs. proactive IO.

    Reactive heisst dein Programm lässt sich benachrichtigen wenn es was machen kann, und reagiert auf diese Benachrichtigung indem es was macht.
    select() -> read(non-blocking aber synchron, Daten stehen bereits in eine Puffer des OS und werden direkt im read-Auftuf in den Puffer das Applikation kopiert).

    Proactive heisst dein Programm sagt dem OS vorab schonmal was es machen soll, und bekommt dann eine Benachrichtigung vom OS wenn die Operation abgeschlossen wurde (egal ob jetzt mit Fehler oder Erfolg).
    BeginRead() -> Daten werden irgendwann im Hintergrund gelesen und in den Puffer der Applikation kopiert -> Callback -> EndRead()

    Der Unterschied was Cancellation angeht...

    Bei reactive gibt es keine "ausständigen" IOs, d.h. es gibt auch nichts zu canceln. Nur dann wenn man die "jetzt ginge was" Benachrichtigungen auf einem (oder mehreren) anderen Threads annimmt, als der wo man ein Objekt zerstören will, muss man etwas aufpassen.

    Bei proactive dagegen hast du einen oder mehrere IOs ausständig, die jederzeit abgeschlossen werden können. Wenn du dein Objekt zerstören willst, musst du nun entweder sicherstellen dass vorher alle Benachrichtigungen verarbeitet wurden, oder dass du bei den Benachrichtigungen irgendwie mitbekommst dass das Objekt bereits zerstört wurde (oder dabei ist zerstört zu werden -- z.B. über die Verwendung eines weak_ptr ).
    Beide Varianten sind allerdings lästig, und auch nicht ganz trivial fehlerfrei hinzubekommen.
    (Der Puffer muss natürlich auch gültig bleiben bis die Operation abgeschlossen wurde.)

    Wobei man auch unter Windows reactive IO verwenden kann. Und auch unter Linux proactive IO.



  • Okay, eure Antworten waren sehr hilfreich! Ich kannte bisher den Unterschied zwischen Events und Delegates leider nicht, ihr habt mir da sehr geholfen. Was ich mich nun gefragt hab ist folgendes:

    //PSEUDO-CODE
    MeinTCPClient tcp1;
    
    //-------------
    
    void MeineProc {
     //die soll aufgerufen werden, wenn ein neuer Client connected
    }
    
    tcp1.OnConnect = MeineProc;
    

    Wenn das mein Code wäre, könnte ich doch innerhalb der Klasse "MeinTCPClient" die Methode (ich glaub ihr habt das Handler genannt), die ich hier übergebe (Meine Proc) in einem anderen Thread ausführen oder? [Aber so, dass hierbei die Klasse und nicht etwa meine main.cpp steuert, ob das ganze synchron oder asynchron zum main - Programm läuft. Ich hoffe ihr versteht, was ich meine. Vielen Dank!



  • hustbaer schrieb:

    Er meint reactive IO vs. proactive IO. [...]

    Ok, danke, jetzt habe ich verstanden, was ihr meint. Hatte nur eine vage Idee, wofür "select" da ist.


Anmelden zum Antworten