std::threads in bestimmter Reihenfolge?
-
Wie gesagt: Um den Fortschrittsbalken zu aktualisieren.
Eigentlich sind doch die Zeiten wo das bequemer (für den Programmierer) war vorbei oder ? Heutzutage ist doch nen Threadwechsel via Events(die man eh hat) nen einzeiler (Dank boost, Qt und co)^^
Dafür benutze ich SendMessage und WM_SETTEXT, schon seit einiger Zeit und das funktioniert.
Versteh ich das richtig ? SendMessage ist die Winapi funktion ? und du holst Dir das Windowshandle eines anderen Prozesses ? und schickst dem Text ?
Oder steh ich aufm Schlauch ?Berechtigte Angst? Bis jetzt (2 Tage testen) hats imer geklappt aber ich hab ein ungutes Gefühl dabei. Und ist die Lösung die threads quasi hintereinander zu queuen in diesem Kontext sinnvoll oder gibts für so eine Anwendung noch etwas einfacheres/besseres?
jedesmal wenn du tippst(das textchange bekommst), machst du einen neuen thread auf, parametrierst den und "schickst den ab" ...
Theorethisch kann es passieren, das sich die textchanges überholen .... aber praktisch isses eher unwahrscheinlich.
Was mir mehr Sorgen machen wuerde ist die Performance / ressourcenverbrauch ^^
Bei jeden tippen nen thread ist ...aehm ... sehr verschwenderisch^^ WIe oft bekommst du beim tipen so nen textchange? nach jedem Buchstaben ?
Besser nur einen thread, den text in ne queue und per event informieren, der thread holt sich den text raus und arbeit es ab (SendMessage) ...Ciao ...
-
tntnet schrieb:
Das sind 2 unterschiedliche Aufgaben. Zum einen einen Fortschrittsbalken anzuzeigen und zum anderen auf den Abschluss einer Aufgabe reagieren. Die sind sicher nicht ganz unabhängig.
Ich sehe keinen kein Problem darin 2 Aufgaben in einer Funktion zu lösen, da die noch nicht einmal unabhängig sind.
tntnet schrieb:
Ein Event ist die richtige Lösung. Und darauf zu verzichten und das auch noch zu begründen, dass man damit ja einen Fortschrittsbalken aktualisieren kann ist doch ein wenig bequem
.Sehe ich nicht so.
1. Entkopplung:
- Der Hintergrund-Thread hat keine Refernzen ins GUI (kann dementsprechen auch ohne GUI oder in einer Konsolenumgebung laufen).
- Egal was der Hintergrund-Thread macht, das GUI bleibt ansprechbar.2. Ereignissteuerung kann schnell kompliziert werden, besonders im Fehlerfall.
3. Wenn etwas im Hintergrund passiert, sollte es sich in jedem Fall in der GUI wiederspiegeln.
Ja, die Timer/Thread Lösung ist einfach (und stabil), deswegen setze ich sie immer ein, es sei denn es spricht irgend etwas dagegen.
Eigentlich sind doch die Zeiten wo das bequemer (für den Programmierer) war vorbei oder ? Heutzutage ist doch nen Threadwechsel via Events(die man eh hat) nen einzeiler (Dank boost, Qt und co)^^
Asynchron kommunikation ist nie einfach. Es gibt im Wesentlichen zwei Probleme:
1. Je mehr gewartet werden muss, desto langsamer wird es bis hin zur völligen Serialisierung, so dass der Thread keinen Sinn mehr macht (man merkt das womöglich nicht).
2. Deadlock: Je mehr hin und her geht desto wahrscheinlich tritt einer auf.
Ob Einzeiler oder nicht is relativ nebensächlich.
-
RHBaum schrieb:
Versteh ich das richtig ? SendMessage ist die Winapi funktion ? und du holst Dir das Windowshandle eines anderen Prozesses ? und schickst dem Text ?
Korrekt, genau so läufts

RHBaum schrieb:
jedesmal wenn du tippst(das textchange bekommst), machst du einen neuen thread auf, parametrierst den und "schickst den ab" ...
Theorethisch kann es passieren, das sich die textchanges überholen .... aber praktisch isses eher unwahrscheinlich.
Was mir mehr Sorgen machen wuerde ist die Performance / ressourcenverbrauch ^^
Bei jeden tippen nen thread ist ...aehm ... sehr verschwenderisch^^ WIe oft bekommst du beim tipen so nen textchange? nach jedem Buchstaben ?Genau, nach jedem Buchstaben beim Tippen.
Also dass das teuer ist stimmt wohl schon, aber seit dem auslagern in einen Hintergrund thread läuft die Textbox wunderbar flüssig auch bei sehr langen Texten und bei sehr schnellem tippen. Davor (ohne thread) hat es bei längeren Texten geruckelt (wahrscheinlich weil erstmal der ganze string in den Kontext des anderen Prozesses geschoben werden muss?).
Problem ist halt dass ich auf die externe Anwendung auch keinen Zugriff habe (ist kein Sourcecode oder ähnliches verfügbar), deswegen bleibt mir nichts anderes übrig als das so zu "hacken".
RHBaum schrieb:
Besser nur einen thread, den text in ne queue und per event informieren, der thread holt sich den text raus und arbeit es ab (SendMessage) ...
Hm, also eine
std::queue<std::string>für den Text? Und bei jedem Textchanged dann einen Event abfeuern?Es muss halt schon auch sichergestellt sein dass ein Text auch wirklich ankommt... also nicht dass zwischen der Abarbeitung der queue der Nutzer dann das Textbox Fenster schließt und der Text dann im Nirvana verschwindet...
-
happystudent
Ich denke, du kannst die den Thread sparen, wenn du PostMessage(...) -> Asynchron statt SendMessage(...) -> synchron (wartet auf Rückmeldung) verwendest.
-
coder777 schrieb:
happystudent
Ich denke, du kannst die den Thread sparen, wenn du PostMessage(...) -> Asynchron statt SendMessage(...) -> synchron (wartet auf Rückmeldung) verwendest.
Ne,
PostMessagegeht nicht mit Pointer-Parametern...
-
Ne, PostMessage geht nicht mit Pointer-Parametern...
Das stimmt.
-
coder777 schrieb:
Das stimmt.
Ja, das ist das Problem. Sonst würde ich einfach PostMessage verwenden und fertig. Am liebsten hätte ich einen C++ Wrapper um SendMessage, der PostMessage nachbildet. Falls es sowas schon gibt, immer her damit

Darüber hinaus kann ich aber deinen Argumenten nicht folgen:
coder777 schrieb:
1. Entkopplung:
- Der Hintergrund-Thread hat keine Refernzen ins GUI (kann dementsprechen auch ohne GUI oder in einer Konsolenumgebung laufen).
- Egal was der Hintergrund-Thread macht, das GUI bleibt ansprechbar.Das ist bei Events auch gegeben?
coder777 schrieb:
3. Wenn etwas im Hintergrund passiert, sollte es sich in jedem Fall in der GUI wiederspiegeln.
Kann es ja auch mit Events, das schließt sich ja nicht aus?
coder777 schrieb:
2. Ereignissteuerung kann schnell kompliziert werden, besonders im Fehlerfall.
Reine Geschmacksache würde ich sagen. Hab in C# schon viele Event-basierte GUIs gebaut und finde das sehr schön einfach und gut nachvollziehbar.
coder777 schrieb:
1. Je mehr gewartet werden muss, desto langsamer wird es bis hin zur völligen Serialisierung, so dass der Thread keinen Sinn mehr macht (man merkt das womöglich nicht).
Eine Aufgabe dauert so lange wie sie dauert.
Warum soll das keinen Sinn machen? Wenn ich per GUI eine Gebäudeheizung einstellen will kann das mal 1-2 Tage dauern bis der Sollwert erreicht ist - wie definierst du überhaupt das etwas "zu lange" braucht und deswegen keinen Sinn mehr macht?
coder777 schrieb:
2. Deadlock: Je mehr hin und her geht desto wahrscheinlich tritt einer auf.
Macht mMn auch keinen Sinn... Ein Deadlock sollte durch richtige locks o.ä. ausgeschlossen werden, ansonsten hat man halt ein verbuggtes (= falsches) Program erstellt. Falsch wird dadurch ja nicht besser dass es etwas seltener Abstürzt? Ein häufiger Deadlock ist mir sogar lieber als ein extrem seltener, weil das einfacher zu debuggen ist.
-
@happystudent
Die Daten steckt man in die Fensterklasse (über Mutex synchronisiert), und dann schickt man perPostMessagenur noch eine "ich hab was in Liste X eingetragen was verarbeitet gehört" Benachrichtigung.Mach' ich oft so, funktioniert wunderbar.
-
hustbaer schrieb:
@happystudent
Die Daten steckt man in die Fensterklasse (über Mutex synchronisiert), und dann schickt man perPostMessagenur noch eine "ich hab was in Liste X eingetragen was verarbeitet gehört" Benachrichtigung.Hm, aber die Fensterklasse (bzw. das Ganze Fenster) gehört ja zu einem externen Prozess... Dann müsste ich ja erstmal in dem fremden Prozess Speicher allozieren und den string dann entsprechend transportieren...
Den Pointer auf den string könnte ich schon per SendMessage verschicken, aber die Adresse passt dann im Zielprozess halt nicht mehr...
Geht das überhaupt alles, oder war die Lösung eher für Fenster gedacht die sich alle im gleichen Prozess aufhalten?
-
happystudent schrieb:
Geht das überhaupt alles, oder war die Lösung eher für Fenster gedacht die sich alle im gleichen Prozess aufhalten?
Ja, das. Sorry, hatte den gesamten Kontext nicht mehr im Kopf. Bzw. ich bin mir gar nicht sicher ob ich das mit der Teilung in zwei Prozesse überhaupt gelesen habe.
happystudent schrieb:
Dafür benutze ich SendMessage und
WM_SETTEXT, schon seit einiger Zeit und das funktioniert. Leider ist das Ganze sehr langsam wenn der Inhalt der Textbox sehr lang wird (SendMessage ist ja synchron und kann auch nicht abgebrochen werden).
(...)
Berechtigte Angst? Bis jetzt (2 Tage testen) hats imer geklappt aber ich hab ein ungutes Gefühl dabei. Und ist die Lösung die threads quasi hintereinander zu queuen in diesem Kontext sinnvoll oder gibts für so eine Anwendung noch etwas einfacheres/besseres?Ich würde da wohl einfach einen eigenen Hilfsthread machen, der so lange am Leben bleibt wie du
WM_SETTEXTverschicken willst.
Der macht dann im Prinzip:void HelperThread::NotifyTextChanged(std::string const& text) { { unique_lock lock(m_mutex); m_text = text; m_textChanged = true; } m_condition.notify_one(); } void HelperThread::ThreadFn() { unique_lock lock(m_mutex); while (true) { m_condition.wait(lock, [&]{ return m_endThread || m_textChanged; }); if (m_endThread) break; std::string text = m_text; m_textChanged = false; // <---- EDIT lock.unlock(); ::SendMessage(m_targetWindowHandle, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(text.c_str())); lock.lock(); } }Das Ruckeln auf der Sender-Seite muss damit auch weg sein, und du hast immer nur einen Thread und schickst die
WM_SETTEXTauch garantiert in der richtigen Reihenfolge.
Und du hast viel weniger Overhead, da du nicht dauernd neue Threads erzeugst und wieder zerstörst.Höchstens die Empfängerseite kann noch "ruckeln" - wenn die
SendMessageAufrufe zu lange brauchen.Ansonsten kannst du natürlich auch einen Shared-Memory Bereich oder eine Shared Data-Section verwenden wo du den Text reinsteckst. Synchronisiert mit ner named interprocess Mutex (Win32 Mutex oder Boost Interprocess). Und bei Änderung ne Message posten oder nen named EVENT setzen (manual reset Event -- oder auch wieder ne Boost Interprocess Condition Variable).
EDIT: m_textChanged = false; vergessen - ohne das würde der Thread ja unnötigerweise dauernd laufen.
-
hustbaer schrieb:
Ich würde da wohl einfach einen eigenen Hilfsthread machen, der so lange am Leben bleibt wie du
WM_SETTEXTverschicken willst.
Der macht dann im Prinzip:Funktioniert perfekt, besten Dank

Damit läuft das einfach viel smoother als jeden SendMessage synchron zu verschicken (und das detachen der threads war mir zu riskant).
hustbaer schrieb:
Höchstens die Empfängerseite kann noch "ruckeln" - wenn die SendMessage Aufrufe zu lange brauchen.
Das stimmt, bei extrem großen Texten kann man das merken wenn man sehr schnell aus dem Textfeld rausklickt. Macht aber gar nix, hauptsache man kann schön schreiben.
-
Ich hab noch ne fehlende Zeile ergänzt. Vermutlich hast du es eh schon selbst gesehen und gefixt - nur für den Fall dass nicht wollte ich den Thread nochmal hoch bringen.
-
hustbaer schrieb:
Ich hab noch ne fehlende Zeile ergänzt. Vermutlich hast du es eh schon selbst gesehen und gefixt - nur für den Fall dass nicht wollte ich den Thread nochmal hoch bringen.
Jo, das hab ich recht schnell gemerkt weil der thread dann permanent in die Textbox geballert hat und gar nix mehr ging

Bin aber schon ziemlich begeistert wie wenig Code das am Ende geworden ist... hatte da mit wesentlich mehr gerechnet
