Wie viele Threads sollte man nutzen?
-
Ethon schrieb:
cooky451 schrieb:
Ethon schrieb:
Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.
Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.
Sagen wir es mal so, du brauchst keinen einzigen Thread mehr als wenn das Feature nicht vorhanden wäre.
Bei einem sychronen Aufruf passiert alles auf deinem Thread. Bei einem asynchronen Aufruf erfolgt der Callback der asynchronen Routine auf einem Kernel-Thread oder aber man schickt dir eine Windows Nachricht. Irgendjemand hat aber diese Nachricht im Kernel auch erzeugen müssen. Da das nicht auf deinem Thread passiert ist, hat das also ein Kernel-Thread getan.
Ein DMA Controller oder was auch immer informiert deine *CPU* (nicht OS), über eine Interruptleitung. Dadurch wird eine Interrupt-Service Routine ausgeführt (nach Rapsos Defintion soll das wohl der Interrupt-Thread sein). ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.
Es würde mich schwer wundern, wenn dein Asynchroner Callback direkt innerhalb der ISR ausführt werden würde. Damit könntest dein ganzes System zum Stillstand bringen, denn während ein Interrupt verarbeitet wird, kann normalerweise kein anderer verarbeitet werden. Deswegen wird in der ISR der oben genannte Kernel Thread informiert, dass jetzt Daten vorliegen. Der macht dann dein Callback.
-
Morle schrieb:
ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.
Es muss natürlich heissen:
ISR sind aber eigentlich keine Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.
-
@rapso: Wenn nicht Kommunikation, wo ist dann der Punkt? OS Scheduling? Ich verstehe auch nicht wirklich, wie du das dann zusammenbasteln willst mit einer einzigen queue. Wenn da jetzt 4 rechenintensive Aufgaben drin stehen, und dahinter { process_gui_stuff(); }, hängt doch alles nur noch? Sicher, die Aufgaben werden 1 ms schneller fertig, aber das ist es doch wohl kaum Wert, wenn der User während der Zeit nichts machen kann. Wenn der GUI Thread durchgängig bei GetMessage() hängt und nur nach "hinten" durchleitet, sollte das wohl kaum Probleme geben. Ja, man verlässt sich auf das OS, aber dafür ist es doch da. Ich versuche wirklich zu sehen wo jetzt das Problem ist, aber ich verstehe es einfach nicht.
-
Morle schrieb:
rapso schrieb:
es ist eine notloesung die durch 'bei mir lief das toll und einfach' zu einer 'packt alle eure UI in einen thread'-loesung propagiert wurde. es macht keinen sinn eine UI in einen thread zu packen, wenn der funktionsteil in einem anderen thread arbeitet und nicht reagiert. [...] es traegt eher zum gegenteil bei, dadurch dass die 'worker' immer weiter im hintergrund sind, wird die applikation weniger responsive, wenn auch die UI in einem thread arbeitet.
[...]
vielleicht kannst du mir ein beispiel geben wo es sehr sinnig ist und nicht anders sauber machbar ist.Also wenn für dich "Responsiveness" das absolute Ziel ist, von dem nicht abgewichen werden darf, dann hast Du Recht. Für mich spielen aber auch andere Dinge eine Rolle: Der Benutzer darf gerne sein Programmfenster noch verschieben dürfen, während irgendeine komplizierte Berechnung läuft. Gerne er auch die lange Berechnung abbrechen dürfen - auch das geht nur mit einer wenigstens minimal bedienbaren GUI - Responsiveness ist hier zweitrangig.
abbrechen? schon wirft sich die frage auf, "wie" brichst du ab? du kannst nicht einfach einen thread stoppen und killen, das gebe leaks und unvorhergesehene seiteneffekte (z.b. koennte ein thread gerade in einer critical section sein).
du musst also eine interaktionsmoeglichkeit einbauen, einfach nur ein UI thread wuerde das nicht bringen. aber dann, wenn der hintergrundthread abgebrochen werden kann, muss er irgendwie eine granularitaet beigebracht bekommen das zu tun. im schlechten fall ruft er von 100 stellen im code sein "IsRunning()" auf und bei false versucht es ohne memory leaks den aufrufsstack hoch zu kommen, manche werfen sich dann auch einfach eine exception. aber richtig gut ist es wenn man die arbeit dieses threads schon in kleine aufgaben aufteilt, vielleicht sogar mittels einer job-queue. dann kann das system nach jedem kleinen job abfragen, ob es noch weiter geht.
und schwubs kannst du an dieselbe stelle die abfrage der event-queue vom OS einbauen und verarbeiten. macht der user kein input, laeuft alles wie immer, gibt es input, wuerde sich das system drum kuemmern, auf diese weise brauchst du nichtmal threads (wenn es nur um entkoplung geht), der user hat dennoch den vollen kompfor.Man muss also Eingaben verarbeiten (bei Windows in Form von Messages) während man "Arbeitet".
Wie ich schon sagte läuft das in der "Arbeit" darauf hinaus, immer mal wieder ProcessMessages aufzurufen. Man koppelt also "GUI-Arbeit" ganz direkt in seine "Berechnungs-Arbeit" rein (wo bleibt da die von dir angesprochene "saubere Architektur"?).hab ich drueber beschrieben, wo bleibt auf der anderen seite deine entkopplung, wenn du ueberall im code z.b. drauf testen darfst, ob 'cancel' geklickt wurde? welche responsibilitaet erfaehrt der user? welche quality of service in anbetracht dessen, dass er ja mal ein program anders nutzen kann als der programmierer der seine abfragen eingebaut hat.
und das ist kein auswuchs meiner phantasie :D, das sind die empfohlenen arbeitsweisen von OS entwicklern.
statt z.b. einen thread pro socket aufzumachen, nutzt man I/O completion ports, statt einen thread fuer maus und einen fuer keyboard und einen fuer... aufzumachen, nutzt man die windows message pipe, selbst dein arbeitgeber will sicher nicht nur am anfang und am ende deines projektes interaktion und ansonsten in seinem thread leben, sondern zerlegt deine tasks in stuecke die bis 16 manstunden dauern sollten.
Ob das ueberhaupt immer geht? ja! das geht. aber es kann arbeit sein. im nachinein ist es zuviel arbeit (-> thread loesung wird meist genutzt), wenn du es von anfang an machst, geht das erstaunlich gut.Schlimmer noch, man hat eigentlich Calls von einer niederwertigen Schicht in eine viel höhere Schicht rein. Weiterhin setzt es v******, dass man seine Arbeit überhaupt in kleine Pakete teilen kann, um ProcessMessages aufrufen zu können. Nutzt einem wenig, wenn man in einer synchronen Betriebssystemfunktion festhängt.
du bist natuerlich nicht der erste dem das auffaelt, aus diesem grund hat jedes moderne OS fuer jeden fall die asynchronen versionen und aus reponsivness, performance und skalierungssicht wird immer empfohlen darauf zurueckzugreifen.
Oder man kann einfach beides in verschiedene Threads packen und nutzt damit die Preemption von seinem OS, kann Layer sauber trennen und muss sich auch keine Gedanken um synchrone OS-Funktionen machen, etc.
als lazy version ist das natuerlich gaengig, aber es ist halt etwas unkontrollierbares in vielen aspekten. natuerlich kannst du vieles abgeben und damit wirbt man heutzutage auch, du kannst sicherlich auch eine datenbank in lua schreiben und bekommst mit sicherheit eine akzeptable loesung fuer dich. aber wenn jemand dem gegenueber etwas von IBM oder SUN stellt, auch wenn du ehrlich sagen kannst, zu 80% machen die dasselbe, sind es dann die 20% die 10mal mehr zeit kosten weil man sie ordentlich macht und bei der gegenueberstellung machen diese dinge dann den riesen unterschied.
Ich hoffe das reicht dir als Beispiel.
hmm, ich denke es kommt wohl drauf an was das ziel ist beim programmieren. wenn man ein kleines tool einfach quick&dirty haben will, sind ein paar threads drauf gut, kann man sich dann auch in einer scriptsprache erstellen und fertig.
zielt man auf qualitaet, denke ich sollte alles zusammenhaengend gut sein.
-
Morle schrieb:
Ethon schrieb:
cooky451 schrieb:
Ethon schrieb:
Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.
Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.
Sagen wir es mal so, du brauchst keinen einzigen Thread mehr als wenn das Feature nicht vorhanden wäre.
Bei einem sychronen Aufruf passiert alles auf deinem Thread. Bei einem asynchronen Aufruf erfolgt der Callback der asynchronen Routine auf einem Kernel-Thread oder aber man schickt dir eine Windows Nachricht. Irgendjemand hat aber diese Nachricht im Kernel auch erzeugen müssen. Da das nicht auf deinem Thread passiert ist, hat das also ein Kernel-Thread getan.
nein, nicht wirklich, dein user level thread kann kein controller interrupt bekommen. wenn du eine synchrone funktion aufrufst, ruft sie intern eine asynchrone auf und synchronisiert drauf.
das liegt am treibermodel moderner betriebsysteme, es darf keinen status geben oder 'unknown' ist. also hast du deine daten nocht nicht, oder du hast sie, 'bin am empfangen' gibt es nicht.
aus diesem grund koennen treiber abstuerzen die deinen request verarbeitet haben, kann eine hotswap festplatte entfernt werden oder auch dein system in sleep gehen, wenn alles laeuft wie geplant merkt deine applikation davon eigentlich nichts. dazu ist es aber noetig dass es diese trennschicht gibt, denn deine festplatte 'redet' nicht mit 20 programmen gleichzeitig und schickt denen auch keine notification, du schichst mit einer OS funktion ein request an windows, windows verteilt die requests dann an die resource verwalter (treiber), die treiber sind dann an ihrer message queue, empfangen die daten und koennen dann machen was sie wollen.
wenn du z.b. eine teure netzwerkkarte von intel hast, hat die eine CPU drauf und 256MB, die bekommt die requests direkt und meldet sich wieder wenn sie soweit ist per interrupt beim treiber. hast du eine billige soundkarte, dann wird der treiber den ganzen sound transcodieren und mischen etc. vermutlich in einem thread.
aber es wird nie passieren, dass dein applikation thread mehr macht als dem kernel eine aufgabe zur weiterleitung zu geben. sogar ein memory mapped file auf dem du direkt arbeitest wird keine writes direkt an die HDD schicken, sondern page faults ausloesen bei windows, wodurch windows die page als 'modified' markeirt, irgendwann diese modifizierten dann fuer deine app sperrt, dann in die festplatten-controller-treiber-queue steckt und dann wird es geschrieben.Ein DMA Controller oder was auch immer informiert deine *CPU* (nicht OS), über eine Interruptleitung. Dadurch wird eine Interrupt-Service Routine ausgeführt (nach Rapsos Defintion soll das wohl der Interrupt-Thread sein). ISR sind aber eigentlich Threads (zumindest nicht im OS Sinne), denn mit Threads ist ein Kontext assoziiert, mit einer ISR erstmal nicht.
eine ISR leitet den request an den eigentlichen thread dafuer weiter, ISR sollen ja nur deswegen als proxy dienen, damit kein treiberentwickler dort was kaputmachen kann. sie nehmen daten auf, schicken sie weiter, dazu notifiaction und return. sonst werden interrupts verschluckt. laut meiner definition ist ISR noch der interrupt, der das OS informiert einen interrupt Thread aufzuwecken.
Es würde mich schwer wundern, wenn dein Asynchroner Callback direkt innerhalb der ISR ausführt werden würde. Damit könntest dein ganzes System zum Stillstand bringen, denn während ein Interrupt verarbeitet wird, kann normalerweise kein anderer verarbeitet werden. Deswegen wird in der ISR der oben genannte Kernel Thread informiert, dass jetzt Daten vorliegen. Der macht dann dein Callback.
aber widersprichst du damit nicht deiner aussage selbst?"Bei einem sychronen Aufruf passiert alles auf deinem Thread.".
denn jetzt sagst du, es gibt keine synchronen wege. oder meinst du jetzt der ISR meldet sich direkt beim thread deiner applikation? das passiert nichtmal auf konsolen heutzutage.
-
cooky451 schrieb:
@rapso: Wenn nicht Kommunikation, wo ist dann der Punkt? OS Scheduling? Ich verstehe auch nicht wirklich, wie du das dann zusammenbasteln willst mit einer einzigen queue. Wenn da jetzt 4 rechenintensive Aufgaben drin stehen, und dahinter { process_gui_stuff();
1. es stehen keine rechenintensiven aufgaben drinnen, wenn du weisst, dass eine aufgabe rechenintensiv werden wuerde, teilst du sie auf.
2. process_something ist die eine funktion die herrscht. sagen wir mal du hast einen single thread raytracer, der eine UI mit einem cancel button hat und dazu per netzwerk 100 slaves die tracen.die thread loesung:
-thread fuer deinen tracer
-thread fuer deine UI
-100threads fuer deine slavesfall 1: user klickt 'cancel', dein tracing thread, der einen tag arbeitet an seinem teil muss also alle t mal auf die variable schauen, die der UI thread bekommen hat. er muss alle zeit auch mal eine funktion aufrufen, die das bild aktualisiert wie es nun ausschaut, damit der UI thread das zeigen darf. wenn du das alle t ms machst, braucht ein click vom user t ms bis dein program reagiert. wenn der user das bild refresht wie verrueckt, braucht es t ms bis er etwas neues sieht.
fall 2: 100threads verlangen dynamisch nach neuen arbeitspacketen, deren leistung ist unterschiedlich, jedes arbeitspacket ist unterschiedlich aufwendig, halt sehr flexibel. also stecken diese 100threads in eine queue oder variable oder wie auch immer eine benachrichtigung (oder in 100queues?), wenn sie ein netzwerkpacket erhalten haben, dein thread checkt diese alle 100s und liest die neuen daten ein, verarbeitet diese und erstellt neue arbeitspackete aufgrund der neuen daten.die single-thread event-queue loesung:
-du nutzt der einfachheit halber die windows message queue, diese beinhaltet sowohl den user input als auch socket events.dein loop sieht in etwa so aus
while(true) { while(peekmessage(msg)) process(msg); if(IsRunning()) { tracejob(); UpdateImage(); } }
(das ist keine loesung um alle thread loesungen zu ersetzen, sondern nur ein beispiel fuer diesen speziellen fall!)
fall 1. statt von deinem thread, nimmt sich das program die message direkt von windows.
fall 2. statt von den 100threads, nimmt sich das program die message ..ich sehe keine bessere responsiveness durch threads, sowohl bei user input als auch bei netzwerk zugriff auf den scheduler. der user interagiert mit der UI mit einem grund, er will 1. es abbrechen 2. aktualisieren, obwohl im thread modus beide buttons scheinbar sofort reagieren (weil sie sich animieren), bricht das program weder ab, noch aktualisiert sich etwas.
es verbirgt eher durch die suggerierung einer aktion, dass nichts passiert. im zweiten fall, da wird sich der programmierer einfallen lassen muessen wie er 'tracejob' feiner macht, damit es feedback gibt. wenn ein user beide programme taeglich bedient, ich denke nicht, dass die thread loesung ihm besser gefaellt.
}, hängt doch alles nur noch? Sicher, die Aufgaben werden 1 ms schneller fertig, aber das ist es doch wohl kaum Wert, wenn der User während der Zeit nichts machen kann. Wenn der GUI Thread durchgängig bei GetMessage() hängt und nur nach "hinten" durchleitet, sollte das wohl kaum Probleme geben. Ja, man verlässt sich auf das OS, aber dafür ist es doch da. Ich versuche wirklich zu sehen wo jetzt das Problem ist, aber ich verstehe es einfach nicht.
es geht mir darum dass es erstmal nichts bringt. natuerlich kann der user dann das fenster resizen oder menues aufmachen die ausgegraut sind weil "waehrend des compiliervorgangs koennen sie nicht speichern" oder sowas, aber das ist nicht was responsivitaet ist, sondern nur eine illusion davon.
wenn du willst dass die UI responsiv ist, musst du auch die dahinterstehenden strukturen/algorithmen etc. responsiv machen, und wenn du das machst, dann wirst du keinen thread mehr brauchen, wozu auch?
-
ich glaube fast wir sollten uns dafuer eher im pub treffen , das sind ja gebete dich ich da tippe
-
Nenenene, 1 GUI Thread, 1 Background Thread. Nix 100 Threads für jeden Clienten. Wenn der Background-Thread etwa alle 15ms checkt was läuft (<.<), dürfte der eine atomic access so gut wie keinen Einfluss auf die Performance haben. Wenn der User also abbrechen klickt, ist nach durchschnittlich 7.5, spätestens nach 15 ms alles abgebrochen. Das ist für den User so gut wie instant.
rapso schrieb:
es stehen keine rechenintensiven aufgaben drinnen, wenn du weisst, dass eine aufgabe rechenintensiv werden wuerde, teilst du sie auf.
Also wenn ich eine Matrix Lösen will dann teile ich das in 1000 kleine Aufgaben ein und jage alles durch einen großen Scheduler damit zwischendurch auch mal der GUI Kram dran kommt? Das halte ich 1. für wesentlich umständlicher, 2. für wesentlich unperformanter und 3. löst es das Problem nicht, wenn 100 dieser Päckchen hintereinander stehen, muss ein GUI Paket immer noch ewig warten. Nein, man braucht einfach getrennte queues.
rapso schrieb:
ich glaube fast wir sollten uns dafuer eher im pub treffen , das sind ja gebete dich ich da tippe
Hehe ich fürchte nur die Fahrtzeit von Aachen aus macht das wieder ineffektiv.
Am schönsten wäre natürlich, wenn man von "außen" in einem Thread eine Exception auslösen könnte, dann müssten die Algorithmen selbst nicht mal mehr die Checks einbauen. Aber sowas gibt's wohl noch nicht. Und man müsste auch irgendwie sicherstellen, dass der andere Thread nicht gerade dabei ist eine Ressource zu reservieren, alles nicht so leicht. Aber eine vollständige Entkopplung von Thread Zeug und Algorithmus wäre wirklich toll.
-
cooky451 schrieb:
Ethon schrieb:
Denkst du? Zb asynchrones Lesen von einer Datei heißt ja im Optimalfall dass das OS eine DMA-Aktion startet und den Auftraggeber informiert sobald der Controller seinen ganzen Krempel in den RAM geschrieben hat. Da hat das OS/die CPU ja 0.0 Rechenaufwand dabei.
Von Rechenaufwand hat niemand gesprochen, nen Thread brauchst du trotzdem dafür.
Nein, brauchst du nicht.
-
cooky451 schrieb:
und 3. löst es das Problem nicht, wenn 100 dieser Päckchen hintereinander stehen, muss ein GUI Paket immer noch ewig warten. Nein, man braucht einfach getrennte queues.
Für sowas gibt's priority-queues.
-
Schon klar, aber welchen Vorteil hat das? (Gegenüber Threads) Es wird nur noch komplizierter (und ineffizienter) - GUI hat keine bestimmte Priorität, sie soll einfach in festen Intervallen gecheckt werden, und das ist ziemlich genau das, was der OS Scheduler macht.
-
rapso schrieb:
abbrechen? schon wirft sich die frage auf, "wie" brichst du ab? du kannst nicht einfach einen thread stoppen und killen, das gebe leaks und unvorhergesehene seiteneffekte (z.b. koennte ein thread gerade in einer critical section sein).
"Abbrechen" ist ein Implementationsdetail um das es mir hier eigentlich gar nicht ging, aber:
du musst also eine interaktionsmoeglichkeit einbauen, einfach nur ein UI thread wuerde das nicht bringen. aber dann, wenn der hintergrundthread abgebrochen werden kann, muss er irgendwie eine granularitaet beigebracht bekommen das zu tun. im schlechten fall ruft er von 100 stellen im code sein "IsRunning()" auf und bei false versucht es ohne memory leaks den aufrufsstack hoch zu kommen,
Wenn man seine Arbeit nicht in kleine Pakete unterteilen kann, dann kann ein "IsRunning" das Mittel der Wahl sein. Es ist aber Designtechnisch meiner Ansicht nach auf jeden Fall besser Aufrufe a la
void OnButtonClick() { myWorker->SetRunning(false); }
Und dann im Thread auf eine Threadvariable "isRunning" zu testen, als im Thread direkte Aufrufe zurück in die GUI zu haben.
statt z.b. einen thread pro socket aufzumachen, nutzt man I/O completion ports, statt einen thread fuer maus und einen fuer keyboard und einen fuer... aufzumachen, nutzt man die windows message pipe,
Was nutzt man denn bei IO-Completion Ports letztendlich? Threads, nur das diese halt im Kernel angesiedelt sind. IOCompletion Ports machen es nur einfacher das Worker-Thread Prinzip umzusetzen. Ich kann aber auch genausogut im Userlevel ein select auf nen Filedescriptor machen und dann die Arbeit auf Worker verteilen (nur nicht so effizient wie das die OS-Entwickler machen können: sie können sich den zentralen Thread den ich fürs select bräuchte ggf. sparen und können aus den IO-Routinen die Arbeit direkt an die Worker geben).
Abgesehen davon hat man da genau das selbe Performanceproblem: Wenn aktuell keine Rechenzeit zur Verfügung steht aber ein IO-Request fertiggestellt worden ist, dann muss der IO-Completion-Port-Worker-Thread (puh!) im Kernel genauso drauf warten bis er gnädigerweise vom Scheduler mal unblockt wird, wie es auch ein Userlevelthread müsste.rapso schrieb:
Morle schrieb:
Bei einem sychronen Aufruf passiert alles auf deinem Thread. Bei einem asynchronen Aufruf erfolgt der Callback der asynchronen Routine auf einem Kernel-Thread oder aber man schickt dir eine Windows Nachricht. Irgendjemand hat aber diese Nachricht im Kernel auch erzeugen müssen. Da das nicht auf deinem Thread passiert ist, hat das also ein Kernel-Thread getan.
nein, nicht wirklich, dein user level thread kann kein controller interrupt bekommen. wenn du eine synchrone funktion aufrufst, ruft sie intern eine asynchrone auf und synchronisiert drauf.
Wodrauf ich hinaus wollte ist, dass die beim Aufruf einer synchronen Funktion die Antwort auf "deinem" Thread bekommst. d.h. dein Callstack führt in eine OS Funktion und beim Daten abholen führt dieser entsprechend zurück. Wie viele Threads da im Hintergrund im OS arbeiten ist erstmal *unbekannt* und hängt von der Implementierung des OS ab. z.B. habe ich mal gelesen dass das Lesen von Daten aus einer Datei, die sich schom im Cache befindet, bei WinNT direkt "durch" geht, ohne dass da nochmal extra Threads arbeiten. Bin mir aber nicht sicher; denkbar wäre es jedenfalls.
Bei asynchronen Callbacks ist es jedoch ganz offensichtlich, dass der Callback auf einem seperaten Thread erfolgt und somit mehrere Threads beteiligt sein müssen. Denn dein Thread der die asynchrone Funktion in Auftrag gegeben hat, kann sich bezüglich seines Callstacks irgendwo in deinem Programm befinden und die Callback-Funktion wird aus einem OS-Kontext aus aufgerufen. Oder aber man schickt dir halt eine Windows-Nachricht.
Zu argumentieren, dass asynchrone Funktionen generell besser wären, weil man sich dann Threads sparen kann, ist also Blödsinn. Man spart sich Userlevel-Threads, aber die Kernelthreads sind trotzdem vorhanden. Nur weil man sie nicht direkt sieht, sind sie aber trotzdem vorhanden!
Nur hat man natürlich bei asynchronen Funktionen den Vorteil, dass diese ganzen Details wie Workerthreads usw vor einem verborgen im OS-Teilen passieren und dort wie gesagt andere Optimierungsmöglichkeiten existieren.rapso schrieb:
ich sehe keine bessere responsiveness durch threads, sowohl bei user input als auch bei netzwerk zugriff auf den scheduler. der user interagiert mit der UI mit einem grund, er will 1. es abbrechen 2. aktualisieren, obwohl im thread modus beide buttons scheinbar sofort reagieren (weil sie sich animieren), bricht das program weder ab, noch aktualisiert sich etwas.
Natürlich siehst Du keine Vorteile; Du hast ja auch das Beispiel so gewählt, dass es keinen Vorteil bringt Threads zu nutzen (ich gehe implizit davon aus, dass Du nur einen Kern hast, denn mit deiner MessageQueue Lösung kannst ja eh nicht mehr als einen Kern nutzen). In diesem Fall bedeutet jegliche Thread-Lösung ja nur zusätzlichen Overhead. Weiterhin nimmst ja als Metrik für Vorteilhaftigkeit der beiden Lösungen weiterhin nur ausschliesslich "Responsiveness" und lässt designtechnische Aspekte aussen vor.
-
Was spricht dagegen in der ISR kurz dem Thread, der die asynchrone Operation gestartet hat, ne Completion-Nachricht zu hinterlegen die dieser sich abrufen kann?
-
Ethon schrieb:
Was spricht dagegen in der ISR kurz dem Thread, der die asynchrone Operation gestartet hat, ne Completion-Nachricht zu hinterlegen die dieser sich abrufen kann?
Nix spricht dagegen, wird ja im Prinzip genau so gemacht (z.B. bei IO Completion Ports).
Nur dass die eigentliche Arbeit nicht im ISR sondern in einem DPC (Deferred Procedure Call) gemacht wird.
Der ISR fordert den DPC an, und tut sonst quasi nix. Maximal noch die Hardware für den nächsten IO programmieren. Der DPC macht dann den Rest. Grund für diese Aufteilung ist dass man sonst zu viel mit dem ISR synchronisieren müsste, und dadurch ne unvorteilhaft hohe Interrupt-Latency bekäme.