Arbeiten mit Events.



  • Gibt es nicht in Standard C++. Lebev und libevent bieten so etwas an, ich habe es aber selber nie benutzt.

    Wenn du nicht nur mit dem Creator arbeitest, sondern mit Qt, kannst du die Qt Eventloop verwenden => siehe Qt Doku



  • Arcoth schrieb:

    Boost.Signals bietet etwas fertiges an. Natürlich kannst du dir auch etwas minimalistisches selber basteln.

    Signals sind synchron, Events in der Regel asynchron. Je nach Anwendungsfall passt das also nicht.



  • Unterstützt C++ das nicht wie andere Sprachen von Haus aus?

    Und ja das ganze sollte asynchron sein. Ich benutze den QT Creator nur als IDE, programmieren tue ich allerdings ohne die QT Libs ..



  • Kannst Du mir bitte etwas mehr über das "Raise" erzählen? Ich finde das in der Delphi-Doku nur in Bezug auf Exceptions... Würde gerne verstehen, was Delphi da von Haus aus kann.





  • Asynchrone Events sind eine sehr schlechte Idee. Das kombiniert die Nachteile von Threads und Events und bringt keine Vorteile. Entweder synchrone Events oder Threads benutzen.



  • nwp3 schrieb:

    Asynchrone Events sind eine sehr schlechte Idee. Das kombiniert die Nachteile von Threads und Events und bringt keine Vorteile. Entweder synchrone Events oder Threads benutzen.

    Events sind asynchron. Das hat mit Threads nichts zu tun.



  • Es geht hier sicherlich darum, dass gewisse "Events" in einem spezifischen Thread abgearbeitet werden müssen (zumeist auferlegt durch Einschränkungen der GUI-API)?



  • Dass das von der GUI-API abhängig ist, dass C++ da nicht wirklich etwas anbieten kann (außer mitzuhelfen durch thread-sichere Queues oder ähnlichem, was ja mit einem der nächsten C++-Standard mitkommt, glaube ich gelesen zu haben)



  • Bei synchronen Events wird im Programm immer nur ein Event gleichzeitig abgearbeitet (das Betriebssystem arbeitet im Hintergrund noch an gestellten Aufgaben). Das hat den gigantischen Vorteil, dass man keine Dataraces hat, keine Locks braucht und damit auch keine Deadlocks bauen kann. Der Nachteil ist, dass sie etwas umständlich zu programmieren sind.
    Threads sind viel einfacher zu programmieren und haben bessere Performance, aber man kriegt Probleme mit Locks und Dataraces.
    Asynchrone Events sind umständlich zu programmieren und haben zusätzlich Dataraces und Deadlockprobleme. Wieso sollte man sowas jemals wollen?



  • Asynchrone Events sind umständlich zu programmieren und haben zusätzlich Dataraces und Deadlockprobleme. Wieso sollte man sowas jemals wollen?

    Wenn man Devices wie einen Comport hat, Daten liesst und kein Busy waiting haben moechte bzw. wenn ich Pakete verarbeiten will, wenn ich Zeit habe ...



  • Frolo schrieb:

    Sry kein Raise: http://www.delphi-treff.de/tutorials/vcl/komponenten-entwicklen/ereignisse-events/

    Das sieht nach typischem GUI-Kram. Was Du meinst ist nicht "raise" sondern "delegates". QT regelt sowas mit seinem Signal-Slot-Konzept. Wenn Du eh schon QT verwendest, dann schau dir das doch mal an.

    Der "GUI-Kram" funktioniert in der Regel so, dass es da einen "GUI-Thread" gibt, der im Wesentlichen auf irgendwelche Ereignisse wie Benutzereingaben, Mouseklicks (etc) wartet und entsprechende Handler, die vorher registriert werden können, aufruft. Wenn du jetzt keine solche GUI-Anwendung baust, dann musst du dir ggf selbst so einen Event-Loop bauen oder es irgendwie anders machen. Für Netzwerk-Kram gibt's da sicherlich auch schon Sachen.

    So etwas ähnliches wie "delegates" kannst du in C++11 auch mit std::function und Lambdas bekommen:

    #include <iostream>
    #include <functional>
    
    void machdat(std::function<void(int)> func)
    {
        func(42);
    }
    
    struct clazz
    {
        void blah(int number) const
        { std::cout << number << std::endl; }
    };
    
    int main()
    {
        clazz obj;
        machdat([&](int num){obj.blah(num);});
        return 0;
    }
    


  • knivil schrieb:

    Asynchrone Events sind umständlich zu programmieren und haben zusätzlich Dataraces und Deadlockprobleme. Wieso sollte man sowas jemals wollen?

    Wenn man Devices wie einen Comport hat, Daten liesst und kein Busy waiting haben moechte bzw. wenn ich Pakete verarbeiten will, wenn ich Zeit habe ...

    dann verwendet man entweder eine "blocking API" (wo ein Leseversuch solange blockiert, bis was da ist, ohne dass das CPU-Zyklen verbrät) innerhalb eines eigenen Threads ... oder arbeitet mit 'nem Event-Loop, der, wenn was anliegt, Handler aufruft, die schnell fertig werden und dabei ggf neue Events anstoßen. Das ist recht ätzend zu programmieren, weil man sich irgendwo einen Zustand merken muss. Deswegen hat Microsoft dafür auch eine Lösung für C# zu bieten: async/Task<>. Die Programme sehen da fast so aus, wie die Versionen, die blockierende APIs verwenden. Unter der Haube baut der Compiler dann aus den Task<> - return enden async -Funktionen einen Zustandsautomaten und macht die Funktion damit "resumable". In C++ haben wir so etwas aber (noch) nicht. Es gibt aber immerhin ein Proposal für "resumable functions".

    Ich wüsst aber auch gerne, wie man das eigentlich "richtig" in C++ machen würde, mit den Mitteln, die aktuell zur Verfügung stehen. Das ist einfach nicht mein Gebiet und hab deswegen da nicht die Erfahrung und kenne auch kaum Bibliotheken in der Hinsicht.

    Ich hatte mal was von dem "proactor model" gehört, was Boost.ASIO zu Grunde legen soll. Aber ich hatte bisher keinen Nerv, mir das alles durchzulesen.



  • In C++ haben wir so etwas aber (noch) nicht. Es gibt aber immerhin ein Proposal für "resumable functions".

    Wenn du Coroutinen fuer C++ meinst, die halte ich persoenlich fuer Bockmist. Aber vielleicht gefaellt es mir, wenn es fertig ist.

    Leseversuch solange blockiert

    Kommt beispielsweise nicht in Frage, wenn der Anwender die Anwendung schliesst, aber ein Read in einem anderen Thread auf sich warten laesst. boost::asio ist fuer Comports Overkill.

    Ich wüsst aber auch gerne, wie man das eigentlich "richtig" in C++ machen würde

    Ich verwende das klassische Schema: select + timeout in einem eigenen Thread als "Service".

    Deswegen hat Microsoft dafür auch eine Lösung für C# zu bieten: async/Task<>.

    Sind sie kill-safe?



  • Was ist an boost::asio eigentlich Overkill in Bezug auf COM-Ports? Wenn man sich vor Augen führt, dass boost::asio zB. unter Windows eigentlich nur ein Wrapper um IO-Completion-Ports ist (plus ein bissl Firlefanz für Dinge, die unter XP mit IOCPs noch nicht möglich waren, wie zB. Timer), dann kann der Overkill doch eigentlich gar nicht so groß sein. Ab Vista+ habe ich immer (verhältnismäßig) sehr gerne mit IOCPs gearbeitet. Die Frage ist nur, ob man sich boost antut oder nicht... Sieht halt immer komplizierter aus, als es eigentlich ist, dafür hat man keine Portierarbeit und die Sache ist gut getestet.



  • 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. 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.

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

    //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?



  • #include <functional>
    
    //...
    std::function<void()> handler;
    void somefunc() {}
    handler = somefunc;
    handler();
    


  • 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.



  • 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.


Anmelden zum Antworten