We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

09.2 Threads, volatile

00:00

Formal Metadata

Title
09.2 Threads, volatile
Title of Series
Number of Parts
54
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Germany:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language
Producer

Content Metadata

Subject Area
Genre
Social classOperating systemComputer programmingSmart cardTiefeWell-formed formulaSoftwareProzessorThread (computing)Object-oriented programmingComputer animationDiagram
Social classThread (computing)InternetDatabaseTotal S.A.Programmer (hardware)Computer animation
Thread (computing)CarriagewayParallelenSocial classCountingInstanz <Informatik>Constructor (object-oriented programming)UpdateZahlPriorityNumberOperating systemWeightRun-time systemAudio file formatCodeInternetDatabaseDiagramProgrammer (hardware)User interfaceReal-time operating systemState of matterFirewall (computing)Source codeArmComputer animationDiagram
Thread (computing)DebuggerDiagramComputer animation
Thread (computing)NumberUser interfaceCodeSource codeComputer animation
NumberThread (computing)DebuggerParallelenComputer animation
Generating functionThread (computing)Computer animationDiagram
Installation artCrash (computing)Function (mathematics)Thread (computing)Aktion <Informatik>DiagramComputer animation
Thread (computing)CalculationInternetAktion <Informatik>Computer animation
Expert systemOperating systemVariable (mathematics)Stress (mechanics)MassThread (computing)CoroutineComputer animation
CompilerDirectory (computing)RAMVariable (mathematics)Thread (computing)Atomic nucleusCore dumpOperating systemSupremumCalculationPhysical quantityDiagram
Thread (computing)NumberVariable (mathematics)CodeCompilerState of matterMittelungsverfahrenComputer animation
Thread (computing)NumberComputer animation
Thread (computing)Computer animationDiagram
Variable (mathematics)Interrupt <Informatik>SignalMicrocontrollerCoroutineProgrammer (hardware)CompilerIntelSystems <München>SpeciesComputer animation
Variable (mathematics)ProzessorMicrocontrollerLösung <Mathematik>Query languageSoftware developerComputer animationDiagram
Transcript: German(auto-generated)
Der Gedanke hinter dem Threads war, dass ich ein Programm intern aufsplitten kann, in Fäden. Threads mit D, wogemerkt, nicht Threads mit T, das wären die Bedrohungen, Threads mit D. Das will ich jetzt als allererstes zeigen.
Wie schaffe ich es, dass ein Programm einen zweiten Faden abspaltet. Das hier wäre der erste Thread, und er spaltet einen zweiten Faden ab, einen zweiten Thread. Und das Betriebssystem hat dann den Job, diesen zweiten Thread irgendwie auf die verschiedenen Kerne, die es hoffentlich zur Verfügung hat, zu verteilen, oder sogar verschiedene
Prozessoren zu verteilen, dafür zu sorgen, dass zwei Sachen gleichzeitig passieren. Und wenn man das kann, einen zweiten Thread, dann kann man es auch hinkriegen, dass sich diese Threads nochmal spalten, dass sie sagen, oh, der muss vielleicht nochmal einen zweiten kriegen, oder einen dritten, oder so soll das machen, der müsste hier noch einen dritten kriegen vielleicht, und noch einen vierten, und noch einen fünften,
der könnte sich auch spalten. Der hier abgespalten ist, könnte auch wieder einen neuen bauen, dann könnte er wieder einen neuen bauen, und so weiter. Sie können dann, wenn sie zwei erzeugen können, beliebig viel erzeugen, irgendwann sagt natürlich das Betriebssystem, das Schluss ist, aber bis dahin ist viel Luft. Den allerersten, das will ich zeigen jetzt.
Wie schaffe ich es, den allerersten Thread hier abzuspalten? Ich sage, allererstes ist eigentlich falsch ausgedrückt, wie schaffe ich es, den zweiten abzuspalten? Ich habe sowieso immer mindestens einen Thread, so startet das Betriebssystem, das Programm an, mit einem Thread, es muss ja irgendwas tun, es gibt deshalb mindestens einen Thread, und von diesem Thread spalte ich einen zweiten ab, ich
erzeuge einen neuen, eigenen Thread. Natürlich ist das in der objektorientierten Programmierung wieder so, dass ein Thread einfach durch eine Klasse dargestellt wird, die sinnvollerweise Thread heißt. Sie sagen, der Klasse Thread, baue mal einen neuen, und das war es schon im
Endeffekt, also die versteckt sich etwas tief, System Threading Thread, da steht die Klasse Thread, ist ja doch gar nicht so tief, ich erzähle was, also im Namespace System, daran der Namespace Threading, die Klasse Thread,
stellt so einen Faden, in Anführungszeichen, im Deutschen sagt man nicht Faden, stellt so einen Faden da, so ein Thread da, und ich baue einfach mal einen, System Threading Thread, und was der nun gerne hätte ist, das was er ausführen soll, irgendwie muss ja dieser Thread wissen, was nun
darin laufen soll, was soll der denn nun die ganze Zeit machen, das muss ich hier hinten noch verraten, ich brauche eine Methode, die hier ausgeführt werden soll, die gebe ich Ihnen da, ich schreibe eine ganz blöde Methode hin, die mache ich
privat, weil außen braucht ja keiner zu sehen, die braucht ja sonst keiner, außerhalb dieser Klasse, und nenne die sehr einfallslos, do work, tu irgendwelche Arbeit, das soll sein was der Thread dann tatsächlich tut, dieser zweite Thread, was hier dann wirklich abgearbeitet wird, der erste
Thread macht das was er sowieso tut, sich um die grafische Oberfläche von meinem Programm kümmern und alle Sachen kümmern, die dadurch aufgerufen werden, was wir bisher gesehen haben, nichts Neues insofern, der zweite Thread kann parallel was anderes tun, und dieses andere, sage ich ihm, einfach hier mit einer
weiteren Methode, das ist das andere was er tut, der zweite Thread wird sich hier um die Methode kümmern, ich baue irgendwas Blödsinniges, um einfach nur Arbeit zu generieren, mal gerade gucken, ich lasse ihn einfach zählen von 0 bis 100
Millionen minus 1, so zählte er dann eben von 0 bis 100 Millionen minus 1, ziemlich schwachsinnige Arbeit, er könnte stattdessen auch das Internet durchsuchen oder in der Datenbank was abfragen, er könnte Pi auf 3 Millionen Stellen berechnen, stellen sich was vernünftigeres vor als dieses
hier, das ist jetzt noch am einfachsten hinzuschreiben, und ich möchte auch sehen was der tut, deshalb baue ich hier noch eine Ausgabe ein, wenn er bei seinem unsinnigen Zählen hier bei Vierfachen von 10 Millionen angekommen ist, 10, 1, 2, 3, 1, 2, 3, gleich 0, so wenn er bei
Vierfachen von 10 Millionen angekommen ist, nicht mit Rest, durch 10 Millionen gleich 0, dann möchte ich einfach eine Ausgabe sehen, die Blödsinn etwas auszugeben, habe ich Ihnen nie verraten, sehen Sie das mal nebenbei, es gibt in .net in System Diagnostics, Diagnostics wie beim
Arzt die Diagnose, in dem Namespace gibt es versteckt zum Beispiel Trace zur Programmverfolgung und diese Klasse hat eine statische Methode namens WriteLine, damit können Sie hier dann unten ins Ausgabefenster schreiben, Sie
müssen nicht irgendwo einen extra Bereich einrichten, im Fenster in dem Sie es schreiben können, sondern Sie können es schön einfach in die Liste hier im Visual Studio schreiben, damit was auch immer da steht und da gebe ich jetzt einfach mal die Zahl aus i durch 10 Millionen, dass er da einfach mitzählt.
Also der Job für den Thread ist eher schwachsinnig, aber so, dass ich auf die Schnelle mal sehen kann, dass er wirklich parallel was tut zu allem anderen, was sonst noch, was sonst läuft, er soll zählen von 0 bis, was habe ich jetzt gesagt, 100 Millionen minus 1 und wenn er ein Vierfaches von 10 Millionen hat,
soll er einfach ausgeben, wievielfache das ist, das zur Kenntnis als Fußnote, wenn Sie sowas brauchen, wie kann ich mitten im Programm einfach mal was ausgeben, ohne extra Fenster aufzumachen, ohne es in ein Label zu schreiben, schön in eine Liste zu schreiben, dass wir dann immer was machen kann. Das ist die Funktion, die Methode, die der Thread bearbeiten
soll, da schreibe ich ihn hier rein, in den Constructor. So, jetzt weiß der Thread, was er tun soll. Ich kann ihn noch ein bisschen weiter einstellen, muss man nicht unbedingt tun, ich tue es trotzdem. Es ist sinnvoll, ihm einen Namen zu geben, wenn sie
100 Threads haben und die heißen alle 7x93, 5x112 und so, stehen sie ein bisschen im Wald beim Debuggen, insofern unbedingt einen Namen geben für jeden Thread, dass sie nachher wissen, was es denn nun ist. Ich nenne ihn jetzt einfach Zähler und ich kann ihm eine Priorität geben, eine Dringlichkeit geben, das
hatte ich schon im Testmanager gezeigt, dass sie für jeden Prozess, für jedes Programm eine Priority vergeben können. Hier können sie jetzt für die einzelnen Threads jeweils eine Priority vergeben. Ist der wichtig oder muss der mal
hin und wieder laufen? Wenn das ein Thread ist, der einfach nur nachguckt, zum Beispiel, ob das Anti-Virus-Programm Update braucht, der ist jetzt nicht so super dringlich, den stellen sie dann auf Priority Lowest hoffentlich. Wenn das ein Thread ist, der irgendwelche Audio-Dateien
berechnet und in Echtzeit ausgibt, wäre das eine schlechte Idee, den auf Lowest zu stellen. Ich stelle ihn jetzt trotzdem immer auf Lowest, das heißt, er läuft am selbsten von allen, er läuft schön langsam. Ich möchte zugucken können, was passiert, also aus didaktischen Gründen schalte ich den jetzt auf Lowest, dass man zugucken kann, was passiert. Bis dahin ist der Thread
nur konfiguriert, er weiß, was er tun soll, er weiß, wie er heißt und er weiß, er sollte sagen, das Betriebssystem weiß, so das Betriebssystem bzw. die .NET Umgebung weiß, wie wichtig der Thread ist und danach kann ich ihn einfach anstarten, so sieht das dann aus.
T-Start, das wäre das Abspalten eines Threads. Ich hoffe, das sieht nicht ganz so bedrohlich, um das Thread mit T aufzugreifen. Ich hoffe, das sieht nicht ganz so bedrohlich aus. Ein Thread, so ein Anführungszeichen, Faden,
Anführungszeichen eines Programms, wird einfach abgebildet in so einer Klassethread, dargestellt durch so eine Instanz der Klassethread. Können und dann laufen zwei Sachen parallel. Dann läuft das Originalprogramm parallel mit dem, was hier in der Methode passiert. Das führe ich doch jetzt
einfach mal irgendwie vor. So, Sie sehen hier unten die Ausgabe, das waren die Ausgaben und dann sehen Sie hier, der Thread-Zähler hat mit Code und so weiter
geendet. Wenn diese Methode, die da aufgerufen worden ist, das sollte ich überhaupt noch mal sagen, diese Methode, die hier aufgerufen worden ist, wenn die am Ende ist oder mit dem Return verlassen wird, wird der Thread beendet. Schlicht und ergreifend. Der hat nichts mehr zu tun. Der bleibt nicht irgendwo im Leben, sondern wird dann auch beseitigt vom Betriebssystem. Das ist nicht immer geschickt.
Manchmal ist das Geschick, den Thread zu behalten und ihm dann demnächst was anderes an Arbeit zu geben, weil das Aufbauen und das Zerstören von Threads Zeit kostet. Aber das ist erstmal das Grundsätzliche hier. Ich sage dem Thread, was er tun soll und wenn er fertig ist mit dem, was er beendet ist, wird der Thread automatisch gestoppt. Also wenn Sie das hier
aufmalen wollen, wäre das so. Der erste Thread existiert, wenn ich mein Programm starte. Ich spalte einen zweiten Thread ab. Der endet irgendwann, aber der erste Thread läuft so lange weiter, bis ich jetzt mein Programm beende. So könnte man das vielleicht aufmalen.
Ist jetzt kein offizielles Diagramm, sondern eine freie Erfindung. Beim Debuggen kann man uns das noch angucken. Wenn ich hier mal einen Breakpunkt
in die Methode, die der Thread aufruft, setze ich mal einen Breakpunkt rein. Lande da drin. Jetzt können wir uns hier bei Debuggen, Fenster, Fenster, Fenster, Threads, grübel, grübel, grübel.
Sie sehen eigentlich laufen hier ganz viele Threads, ohne dass es uns einer erzählt hat. Aber das hier sind jetzt die beiden spannenden. Der Hauptthread ist derjenige, den wir bisher gesehen haben, in dem die
Arbebitte Oberfläche passiert. Und hier gibt es jetzt einen extra Thread namens Zähler. In diesem Fensterchen können Sie auch umschalten. Sie können hier dann sagen, ich möchte jetzt aber mal gucken, wo ich hier zu Thread wechsle. Ich möchte nur mal den anderen Thread angucken von denen. Dann können Sie hin und her schalten. Falls sich einer gewundert hat, wie klappt das überhaupt, dass ich verfolge, dass das Programm verfolge, wenn ich an acht Stellen oder sogar zehn
oder hundert Stellen gleichzeitig bin. Sie schalten einfach dann hier um und sagen, oh gehen wir mal zu dem und möchte wissen, wo der steht. Wenn ich das hier bei dem mache, befürchte ich, der steht irgendwo gerade, wo ich einen Quellcode habe. Der Hauptthread ist ja derjenige mit der Bedienoberfläche. Der steht gerne an Stellen irgendwo in der Bibliothek und nicht bei
Quellcode, den ich geschrieben habe. So sieht das dann aus. Insofern darf ich ganz traurig sein, wenn Sie nicht sehen, was da passiert. Wenn Sie den Code vom Thread selbst geschrieben haben, sehen Sie auch wirklich dann, wo der steht. Ich kann umgekehrt hier noch einen Breakpunkt reinsetzen, den hier
unten mal wieder rausnehmen. Hier oben, der Breakpunkt ist der im Hauptthread, die Ereignisbehandlungsroutine für das Klicken. Das passiert im Hauptthread. Wenn ich hier mal weitermache, ach jetzt läuft der Arbeitsthread nicht mehr wahrscheinlich, das ist ungeschickt. Ich mache erst einmal den an.
Da ist der Hauptthread, aber Sie sehen keinen Zählerthread, der ist ja noch nicht erzeugt. Der war eben gerade beendet, der Zählerthread ist noch nicht erzeugt. Wenn ich jetzt hier mal sage, mach mal weiter und dann hoffentlich sofort hier wieder den Button klicke. Das war nicht schnell genug, ärgerlich,
weil der schon wieder beendet, der andere. Sie sehen zumindest, dass ich hier im Hauptthread bin. Was ich noch zeigen kann, ist, dass ich jetzt mehrere von
den Hilfsthreads, die ich erzeugt habe, parallel erzeugen kann. Mit jedem Mausklick auf den Button, sage ich ja, erzeuge einen neuen Thread. Das heißt, wenn ich jetzt mehrfach auf den Button klicke, werden entsprechend viele Threads erzeugt. Für jeden Klick auf den Button legt er einen neuen Thread an und startet den mit der Arbeit. Das heißt, ich muss dann hier mehrere Ausgaben sehen, die durcheinander laufen.
Ich hoffe, die Übung gelingt. Ich mache mal ganz aus hier. Okay, das wäre jetzt der erste Thread. Ich starte den zweiten. Sie sehen, wie die Zahlen durcheinander gehen. Die gehen durcheinander, weil jetzt mehrere Threads parallel arbeiten.
Mehrere Threads erzählen parallel von 0 bis, was habe ich gesagt, 100 Millionen. Deshalb geht das hier durcheinander. Der erste ist schon, der erste ist bei 10 Millionen, der nächste ist bei 30 Millionen, hier war einer bei 70 Millionen. Deshalb geht das durcheinander. Drei Threads arbeiten parallel. Das müsste man dann sogar auch im Debugger sehen können. Wenn ich
den Rechter Stuhl schicke. Ich setze hier mal einen Breakpunkt, gebe dem aber eine Bedingung. Ah, nicht an der Stelle. Oder? Doch, an der Stelle. Doch, das ist richtig. Ich setze hier einen Breakpunkt und gebe dem eine Bedingung. Nämlich,
nämlich, nämlich, nämlich. Das war die falsche Art von Bedingung. Trefferanzahl. Er möge anhalten, wenn ich fünfmal an der Stelle gewesen bin. Habe ich Ihnen nie verraten, was der Debugger alles so kann. Also, sie können Bedingungen geben. Dieser Breakpunkt soll nur gelten, wenn ich da beim fünften Mal
angekomme. Ich klicke jetzt fünfmal auf den Knopf und dann wird er mir beim fünften Mal hier anhalten. Das Programm läuft noch. Okay, da ist so. Das Programm läuft noch. Eins, zwei, drei, vier, fünf. So, jetzt müsste eigentlich, wenn ich hier bei Threads gucke, sehen Sie, fünf ist wahrscheinlich ein bisschen großzügig gewesen. Sie sehen
zumindest dreimal den Thread-Zähler hier laufen. Parallel. Ich habe ihn tatsächlich geschafft, dreimal parallel starten zu lassen. Wahrscheinlich ist das erste Mal schon wieder beendet. Genau, der fünfte ist ja noch gar nicht gestartet. Der fünfte wird ja erst gestartet. Der erste ist wahrscheinlich schon wieder zu Ende. Das heißt, ich habe hier parallel schon drei
Threads am Laufen. Ohne großen Aufwand. Sobald, das hatte ich besprochen, sobald Sie wissen, wie Sie einen erzeugen können, ist dann keine Aktion, mehrere zu erzeugen. In dieser Schleife könnte ich sogar auch neue Threads erzeugen. Das wäre dann die Situation, dass der
abgespaltene Thread weitere erzeugen kann. Das ist nicht verboten. Das wäre möglich. So, diese Threads sollten, wie erzähle ich das jetzt mal, die Threads laufen typischerweise nicht gerade mal so eben, eine Sekunde,
sondern typischerweise laufen die endlos. Wenn Sie sowas haben, wie ein Thread, der drauf lauscht, was gerade irgendwo aus dem Lande von irgendeiner Anlage gesendet wird oder der bestimmte Internetseiten durchsucht. Ein Thread, der monströse Sammlungen an Daten sortiert. Diese Threads sind nicht
mal gerade eben schnell beendet, sondern laufen vielleicht Minuten, vielleicht Stunden, vielleicht ständig. Ich muss die Möglichkeit haben, einen Thread, der dauerhaft läuft, zu beenden. Das Einfachste ist, dass ich
sage, dieser Thread läuft im Hintergrund. Ich muss mal gerade gucken, wie ich das hier geschickt veranstalte. Für den Lückentext Nummer 3 baue ich einfach nochmal ein 9. Lückentext Nummer 3, ein 9. Und einfach Gänsefüßchen. Seine Funktion heißt dann nicht mehr DoWork, sondern heißt dann ganz kreativ DoWork1. Und
DoWork1, also natürlich auch nicht T, sondern RSTU von mir aus. T1 wäre eigentlich schickter gewesen in der Tat. T1. Jetzt möchte ich hier das DoWork1 zu einer
Endlosschleife machen. Das ist fies. Das heißt, der Thread, den ich da
habe, das wäre außerhalb eines Threads sowieso vernichtend, weil die Oberfläche nicht mehr leben würde. Wenn Sie das im Hauptthread machen, sitzt das Ding in dieser Schleife fest und reagiert auf keinen Klick und keine Tastatureingabe mehr. Das wäre eigentlich ein Programmabsturz, nach üblicher Auffassung. Wenn Sie das hier im Hauptthread machen, in diesem Thread, der so nebenbei
läuft, dass wir keine Aktion machen, bei eben der Endlosschleife, es stört ja keinen. Hier mache ich folgendes. Ich zähle mal wieder mit i gleich 0, nichts
anderes eingefallen ist, was man so auf die Schnelle mal da reinschreiben kann. Sehr geschickt. Wenn ich zählen will, muss ich das sowohl außerhalb der Schleife haben. Ich gucke nach, wenn ich i erhöhe, ist das jetzt hoch genug?
Ist das, was habe ich ausprobiert, auch wieder über 10 Millionen, 1, 2, 3, 1, 2, 3, ist das über 10 Millionen, dann fange ich von vorne an, ganz billig, zwischendurch gebe ich einfach aus, um alle Leute wissen zu lassen, dass ich noch
am Arbeiten bin. Vielleicht kein WriteLine, vielleicht nur ein Write. WriteLine heißt, Ständchen ausgeben und neue Zeile. Mit Write sagen Sie, Ständchen ausgeben, keine neue Zeile. Dann schreibt ihr das alles hintereinander. Da ist die Liste hier unten gleich nicht so voll.
Das hier ist eine ziemlich bürzlinige Funktion, die in einer Endlosschleife von 0 bis 10 Millionen minus 1 zählt und wenn sie am Ende angekommen ist,
wenn sie wieder zurückspringt, ein Sternchen ausgibt. Das ist die Funktion und der zweite Thread kriegt diese Funktion. Ich mache den ersten mal aus, indem ich ihn nicht anstarte. Das ist gut, ich mache ihn aus, indem ich ihn nicht anstarte. Ich starte den ersten Thread gar nicht an. Der Thread von eben, den lasse ich aus.
Den richte ich zwar ein, aber ich starte ihn gar nicht, den lasse ich aus. Den zweiten starte ich und dann hat das folgende Effekt, da ist mein Fensterchen.
Das ist die Sternchen, das ist eine sehr bürzlinige Art Sternchen zu erzeugen. Der Thread zählt durch und jedes Mal wenn er ans Ende gekommen ist, gibt er ein Sternchen aus. Jetzt beende ich meinen Hauptprogramm und das beende natürlich nicht diesen anderen Thread.
Der Thread arbeitet immer noch fleißig. Vorsichtig, wenn Sie Threads einrichten, müssen Sie dafür sorgen, dass die Threads irgendwann enden. Sonst endet Ihr Programm eigentlich nicht offiziell. Der Thread arbeitet jetzt, bis einer den Rechner abschaltet oder hier nählicherweise sagt, stopp mal.
Die üblichen Threads arbeiten tatsächlich in so einer Endlosschleife. Die haben irgendeinen stupiden Job, auf die Maus zu hören, das macht eigentlich der Hauptthread schon, aufs Internet zu hören, Daten zu empfangen, Daten zu senden, irgendwelche Diagramme zu aktualisieren.
Die typischen Threads arbeiten so in einer Endlosschleife und Sie sehen, das ist jetzt natürlich blöd. Ich muss den irgendwie beenden. Das Einfachste ist, dass Sie diesen Thread sagen, er arbeitet mit dem Hintergrund. Das hier ist Background ist gleich True, das ist die einfachste Art.
Das heißt, das System bricht diesen Thread ab, sobald der Hauptthread beendet worden ist. Damit sagen Sie dem System, dieses Ding ist nicht wirklich wichtig, der macht irgendwas im Hintergrund, irgendwelche Aufbäume arbeiten. Wenn der Hauptthread zu Ende ist, bitte auch diesen Thread beenden.
In Aktion, hier macht er seine Sternchen und jetzt beende ich das Programm. Und Sie sehen, es ist auch wirklich beendet. Ich muss hier nicht nochmal extra irgendwo klicken, es ist wirklich beendet. Das ist Background, das ist die simpelste Lösung dafür.
Eine nicht ganz so simple Lösung ist, dass ich diese Endlosschleife in dem Thread hier eigentlich keine Endlosschleife sein lasse, sondern dass ich hier etwas einbaue, um dem
Thread zu sagen, geht es immer gut. Das hier nicht ständig True steht, sondern dass ich dem Thread, wenn es nur Zeit ist, dass ich dem Thread hier sagen kann, jetzt war der letzte Durchgang und dann ist es auch gut. Also hier keine echte Endlosschleife zu haben, sondern eine Schleife, die ich mit eigener Bedingung abbrechen kann.
Das wird jetzt die dritte Variante, die wieder Copy und Paste, die dritte Variante, aber der vierte Lückentext. So, die dritte Variante, der vierte Lückentext, nennen wir ihn T2, wir können es einfach wieder gänseflüssig machen, das Pupsalat, das meiste bleibt so, wie es war.
Ich brauche eine andere Funktion, um wieder in der Arbeit zu verschaffen. T2, T2, T2, aber jetzt hier nicht das XBackground, das natürlich nicht. Jetzt kommt eine andere Lösung, nicht das mit dem XBackground, das ist die ganz simple Lösung.
Das ist systemweise, es darf den Thread beenden, wenn es dem Ende zugeht vom Programm. Und hier möchte ich den jetzt zu Fuß beenden, den Thread. Eine Nummer komplizierter. Die selbe Arie hier, den kopiere ich, jetzt können Sie da auch wieder mit Gänsefüßchen
arbeiten, den kopiere ich, der wird dann Lückentext 4 und heißt DoWork 2. Jetzt will ich hier aber nicht sagen, mach mal diese Schleife bis St. Nimmerlein, sondern die möchte ich abbrechen.
Ich richte eine Variable ein, mit der ich sage, jetzt ist Feierabend, eine Buche Variable, das wird auch Lückentext Nummer 4, eine Buche Variable, mit der mein Hauptthread und dieser Thread kommunizieren können.
Hier habe ich die Must Stop, wollte ich die mal nennen, das ist noch nicht ganz fertig, da kommt gleich noch was dazu, eine technische Ergänzung, aber das ist jetzt zumindest der Gedanke, Must Stop, muss ich gar nicht initialisieren, egal,
der steht sowieso auf Forst und das ist gut. Das möchte ich hier verwenden, eine Variable, mit der ich sagen kann, so jetzt ist Feierabend und dann endet diese Schleife und der Thread geht einfach aus der Schleife raus, kommt
ans Ende von dieser Routine und ist beendet. Diese Variable soll sagen, jetzt Schluss machen, um das vorzuführen mache ich noch einen anderen Button ins Fenster, mit dem ich genau das sagen kann, der Button
soll nichts anderes tun als Must Stop gleich True. Der erste Knopf baut den Thread zusammen, startet ihn und der zweite Knopf kann sagen,
jetzt ist Feierabend, er setzt dieses Must Stop auf True, dann ist diese Endlosschleife keine Endlosschleife mehr, hier steht Weil, Falls, das wird beendet, der Thread läuft
hier raus und gut, erste technische Anmerkung, gibt noch so zwei andere technische Kleinigkeiten, damit das schöner wird, erste technische Anmerkung, hier muss man dann ein Volatile vorschreiben, Flüchtig, Wolle Teil, das neue Schlüsselwort, was wir noch nicht haben.
Es könnte nämlich Folgendes passieren, typischerweise passiert das nicht, aber könnte passieren, man kann sich schwer zu vielen Fehler einbauen, wenn man das vergisst, es könnte Folgendes passieren, dass das Betriebssystem den Hauptthread auf den
ersten Kern setzt, nenne ich hier mal Core 0 von mir aus und das Betriebssystem den zweiten Thread auf den zweiten Kern setzt, und obendrein könnte passieren, dass der
Compiler sagt, oh diese eine Variable Must Stop, lohnt sich gar nicht, dass ich diese Variable im Speicher anlege, im RAM anlege, die Variable lege ich lokal in einem Register auf dem Core an, das heißt, sie steht einmal hier und sie steht einmal hier. Es
ist aufwendig Sachen aus dem großen Speicher, den Gigabyte, von RAM zu holen, das kostet Zeit, das Lesen und das Schreiben aus dem RAM in das RAM kosten Zeit, deshalb versucht der Compiler möglichst viele Sachen lokal zu halten, in den Registern des jeweiligen Cores zu halten. Also wenn der Compiler sich entscheidet, dieses Must Stop
in den Registern zu halten, jeweils auf den einzelnen Cores, kann sein, dass das Hauptprogramm dieses Must Stop auf True setzt, wenn ich es mal vernünftig geschrieben kriege, auf True setzt, aber dass der Nebelthread immer noch ein False sieht,
weil das Kopien derselben Variable sind, die aber dann voneinander getrennt sind. Eklige Geschichte passiert typischerweise nicht, nur jedes tausendste Mal und auch nur auf bestimmten Rechnern. Super blöd zu finden sowas, behalten sie im Hinterkopf, wenn sie sowas haben, wenn sie Variablen haben, die nackt ohne weiteres, gleich
kommt noch eine andere Lösung, wenn sie Variablen haben, die nackt ohne weitere Hilfsmaßnahmen in mehreren Threads verwendet werden, muss man die als Volatile kennzeichnen, damit der Compiler nicht auf solche Gedanken kommt. Gibt noch ein paar andere Geschichten, der Compiler darf auch bestimmte Umsortierungen nicht vornehmen, mich lieber gar nicht darauf eingehen, alles kompliziert, muss man auch gar nicht
im Detail wissen, das Wesentliche ist, vorsichtig, es kann Blödsinn passieren, das sehen Sie daran schon, dass Blödsinn passieren kann, wenn Sie Variablen haben, die von mehreren Threads benutzt werden. Einfachste Lösung, volle Teil davor schreiben, dann ist der Compiler gewarnt, dass da Schweinereien passieren sozusagen,
dass er da nicht optimieren darf auf bestimmte Weise. Das heißt, das Ding müsste so weit funktionieren und das ein bisschen runder zu machen, würde ich folgendes noch machen, ich würde dafür sorgen, dass ich den auch nicht wieder anstarten kann, wenn er läuft,
das war ja eben, hier eben konnte ich einfach dreimal draufklicken und ich hatte drei Threads am Laufen, das ist vielleicht nicht geschickt. Ich baue noch eine andere Variable ein, die nenne ich mal isRunning, mit der ich dafür sorge, dass er nicht neu anstartet,
das wäre jetzt hier, dass er nicht neu anstartet, wenn er schon am Arbeiten ist. If not is running, wenn wir nicht am Laufen sind, machen wir das,
wenn der Thread nicht am Laufen ist, mache ich das und hier muss ich dann sich als
Habe sagen, bevor ich ihn starte, ok, jetzt ist er aber so praktisch am Laufen, hier setze ich das auf true und bevor der Thread beendet wird, sagt er eben schnell noch,
ok, ich laufe nicht mehr, isRunning ist gleich false, ist das kompliziert. Ich versuche das nochmal zu erklären, wo war ich? Hier war ich, ich merke mir in einer
Variable, die beide Threads lesen können, in einer Variable namens isRunning, merke ich mir, ob der Thread gerade am Laufen ist, das führe ich nach, sobald ich ihn starte, schalte ich die auch auf var, die Variable, das hier verbietet mir den Thread zweimal
anzustarten, wenn er am Laufen ist, komme ich hier nicht rein, wenn isRunning true ist, komme ich hier nicht rein, kann ich nicht zum zweiten Mal anstarten. Und dann habe ich die Variable must stop, die ich mit dem anderen Button auf var setze, mit der kann
ich dem Thread signalisieren, jetzt ist Feierabend, keine Endlosschleife mehr. Kucken wir uns das an, mit dem muss er jetzt anfangen, Sie sehen, da fängt er jetzt an zu arbeiten und mit dem hört er dann auf, der Thread Zähler hat mit Code
0 geendet. Wenn ich hier wieder reingehe, fängt er nicht wieder an, oder habe ich jetzt nicht geklickt, super, ein kleiner Fehler, was habe ich da verbockt? Wenn
running an ist, wenn running aussetzt, setze ich es auf an und wenn der hier fertig ist, setzt er es auf aus, must stop wird nicht zurückgesetzt, das habe ich vergessen. Must stop wird von dem zweiten Knopf auf war gesetzt, aber niemand stellt must stop
wieder auf falsch, das sollte ich irgendwo noch erledigen, sinnvollerweise, bevor ich den wieder anschalte, hier sollte ich das erledigen, bevor ich den Thread wieder anschalte, soll ich ihm sagen, es ist noch nicht die Endbedingung erreicht, hier sollte false stehen. Jetzt habe ich eine Stelle, an der must stop auf zugestellt wird, wenn ich sage, abbrechen, der zweite Knopf und hier sage ich beim ersten
Knopf, für den Fall, dass es vorher schon mal abgebrochen worden ist, muss ich es wieder zurücksetzen, dass noch nicht die Zeit ist, es abzubrechen, so jetzt müsste es aber funktionieren, er läuft und läuft und läuft und dann sage ich stopp, okay, der Thread Zähler
wurde beendet und so, das war das Problem und dann beendet er es wieder, so kann man das auch lösen und dann haben sie zum ersten Mal gesehen, wie mehrere Threads miteinander kommunizieren können, also die müssen nicht so nebeneinander herleben, wie ich das hier aufgemalt habe, die können natürlich miteinander
kommunizieren, was das wesentliche ist, sie wollen im Zweifelsfall, dass es der zweite Thread oder dritte, zehnte, hundertste Thread Daten einsammelt, irgendwie muss er die Daten ja übergeben an den Hauptthread oder vielleicht auch Daten versenden und deshalb die Daten beim Hauptthread kriegen, also es ist wesentlich, dass die miteinander kommunizieren, das ist die billigste Art
hier, wie man das machen kann, mit dem Wolle-Teil, das zeige ich Ihnen eigentlich eher aus dem Grund, weil das auch bei den Mikrocontrollern an vielen Stellen vorkommt, sobald sie Interrupts haben, Routinen, die von zum Beispiel von äußeren Signalen angestoßen werden, ist das sehr ähnlich wie die Threads, wenn sie auf so einem Mikrocontroller Variablen
haben, die von ihrem echten Programm, wie von Interrupts benutzt werden, müssen sie auch als Wolle-Teil kennzeichnen, sonst gibt es irgendwann irgendwo Ärger, weil der compiler vielleicht mal auf den Gedanken ist, Sachen an mehreren Stellen lokal zu speichern oder sie umzusortieren oder andere
Schweinereien, mehrere Cores, das Problem hat man typischerweise dann nicht bei den Mikrocontrollern, aber es gibt trotzdem andere Arten, wie man diese Übergabe kaputt kriegen kann, wenn man den compiler nur hinreichend viel optimiert. Das ist eigentlich der Grund, weshalb ich hier Wolle-Teil zeige, im C kommt es auch vor, sobald sie komplizierte Sachen machen, in C
mit Interrupts, Routinen, die insbesondere von außen angestoßen werden beim Mikrocontroller, gehört dann im Zweifelsfall da auch irgendwo ein Wolle-Teil davor. In den modernen Sprachen ist dieses Wolle-Teil eher rustikal, ich zeige gleich ein paar Sachen, wie das ohne das geht, aber
das ist die billige Art, wie man kommunizieren kann zwischen verschiedenen Sweats. Ein Beispiel noch für die Nummer 5, wie Wolle-Teil vorkommen könnte, mal gucken, was wir sinnvollerweise machen, so was hier,
Wolle-Teil float für die Nummer 5, Wolle-Teil float x, sehr unkreativ, dann könnte ich vielleicht hier in der Methode, die die Arbeit macht, hier macht der die Arbeit, könnte ich vielleicht so was einbauen für die Nummer 5, wie x ist
vielleicht, ach was weiß ich, Pi mal i, keine Ahnung, also wenn er hier ans Ende kommt, das ist eigentlich ein bisschen blödsinnig, ja das macht ja
nicht integer my double, aber das ist eigentlich blödsinnig, ich sollte das da rausnehmen, dass auch wirklich was zu sehen ist, Entschuldigung, das sollte ich hier hinsetzen, dass auch wirklich was passiert, die wird natürlich jetzt super langsam, aber sei es so, also in jedem Durchgang, float, hier muss man natürlich casten, das war es, okay, hier muss ich
einmal float casten, i ist ein integer, meine zählvariable, Pi ist ein double, das ganze als float speichern in my mix, es gibt kein Wolle-Teil für double, liegt an den Prozessoren, die üblichen Prozessoren machen bei 32 bit
an der Stelle, gerade mal gucken, also ich schreibe ständig raus, wo ich denn gerade bin beim zählen und jetzt könnte ich ganz dreist noch einen weiteren Knopf einbauen, mit dem ich das einfach abfrage, wo ich den gerade
bin beim zählen, das lohnt sich nicht für den Lückentext, gleich nur eine Zeile für den Lückentext, also ich baue hier noch einen Knopf ein, natürlich jetzt alle bezeichnet, start, stopp und jetzt einer um einen Wert zu holen, das label lebe ich
gleich den Wert aus, so und an der Stelle möchte ich einfach in das label den Wert ausgeben, label, content, content, content, content ist gleich, ich hoffe
doch, das heißt, wenn ich jetzt auf den dritten Button klicke, liest er aus, was der Wert dieser Variable war, die von dem another thread verstellt wird und setzt den ins label rein, wenn das mal funktioniert, ich starte den thread an, ok und jetzt kann
ich hier auslesen, was in dieser Variable steht, also ich kann tatsächlich mitkriegen, was in der another thread stattfindet, indem ich da jetzt eine Variable auslese, die Variable wird von dem Hilfs thread gesetzt und hier kann ich es auslesen, dann müsste
der jetzt ja auch die ganze Zeit auf dem selben Wert bleiben, der läuft ja nicht mehr, ok, das als grundsätzlicher Gedanke, wie ich einen thread erzeugen kann und wie ich auf elementare Art mit dem reden kann, wie gesagt, dieses Wolle-Teil ist rustikal,
das sehen Sie eigentlich seltener, wenn Sie mit C-Sharp und mit Java programmieren, man kann es verwenden, man macht es typischerweise anders, es gibt bessere Lösungen dafür, ich zeige gleich ein paar, wenn Sie Microcontroller programmieren, auf etwas