<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://wiki.delphigl.com/index.php?action=history&amp;feed=atom&amp;title=Tutorial_Multithreading</id>
		<title>Tutorial Multithreading - Versionsgeschichte</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.delphigl.com/index.php?action=history&amp;feed=atom&amp;title=Tutorial_Multithreading"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;action=history"/>
		<updated>2026-04-29T16:40:01Z</updated>
		<subtitle>Versionsgeschichte dieser Seite in DGL Wiki</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=23182&amp;oldid=prev</id>
		<title>Flash: /* Synchronschwimmen */</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=23182&amp;oldid=prev"/>
				<updated>2009-03-22T10:53:44Z</updated>
		
		<summary type="html">&lt;p&gt;‎&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;Synchronschwimmen&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;tr style='vertical-align: top;' lang='de'&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;← Nächstältere Version&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;Version vom 22. März 2009, 10:53 Uhr&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l290&quot; &gt;Zeile 290:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 290:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;In Beispiel 1 muss nicht synchronisiert werden, da die Daten auf die Platte geschrieben werden.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;In Beispiel 1 muss nicht synchronisiert werden, da die Daten auf die Platte geschrieben werden.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Es macht dort keinen Unterschieb ob der Thread unterbrochen wird oder nicht.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Es macht dort keinen Unterschieb ob der Thread unterbrochen wird oder nicht.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;Hinweis&lt;/del&gt;|VORSICHT! Wenn jetzt die gesamten Threads aber mit ein und dem selben FileStream arbeiten dann muss auch synchronisiert werden.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;Warnung&lt;/ins&gt;|VORSICHT! Wenn jetzt die gesamten Threads aber mit ein und dem selben FileStream arbeiten dann muss auch synchronisiert werden.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Da dieser FileStream sozusagen ein und den selbe Speicherbereich darstellt!}}&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Da dieser FileStream sozusagen ein und den selbe Speicherbereich darstellt!}}&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;br&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Flash</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=22954&amp;oldid=prev</id>
		<title>DGLBot: Der Ausdruck ''&lt;pascal&gt;(.*?)&lt;/pascal&gt;'' wurde ersetzt mit ''&lt;source lang=&quot;pascal&quot;&gt;$1&lt;/source&gt;''.</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=22954&amp;oldid=prev"/>
				<updated>2009-03-10T18:13:23Z</updated>
		
		<summary type="html">&lt;p&gt;Der Ausdruck &amp;#039;&amp;#039;&amp;lt;pascal&amp;gt;(.*?)&amp;lt;/pascal&amp;gt;&amp;#039;&amp;#039; wurde ersetzt mit &amp;#039;&amp;#039;&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;$1&amp;lt;/source&amp;gt;&amp;#039;&amp;#039;.&lt;/p&gt;
&lt;a href=&quot;https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;amp;diff=22954&amp;amp;oldid=20214&quot;&gt;Änderungen zeigen&lt;/a&gt;</summary>
		<author><name>DGLBot</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=20214&amp;oldid=prev</id>
		<title>I0n0s: /* Wie kann ich sie denn erstellen? */</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=20214&amp;oldid=prev"/>
				<updated>2007-02-20T10:54:20Z</updated>
		
		<summary type="html">&lt;p&gt;‎&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;Wie kann ich sie denn erstellen?&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;tr style='vertical-align: top;' lang='de'&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;← Nächstältere Version&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;Version vom 20. Februar 2007, 10:54 Uhr&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l59&quot; &gt;Zeile 59:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 59:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;type&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;type&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; TMyOwnThread = class(&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;Thread&lt;/del&gt;)&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; TMyOwnThread = class(&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;TThread&lt;/ins&gt;)&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; protected&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; protected&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; &amp;#160; procedure Execute; override;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;#160;&amp;#160; &amp;#160; procedure Execute; override;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>I0n0s</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=15875&amp;oldid=prev</id>
		<title>MyChaOS am 26. Dezember 2005 um 11:15 Uhr</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=15875&amp;oldid=prev"/>
				<updated>2005-12-26T11:15:22Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;col class='diff-marker' /&gt;
				&lt;col class='diff-content' /&gt;
				&lt;tr style='vertical-align: top;' lang='de'&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;← Nächstältere Version&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black; text-align: center;&quot;&gt;Version vom 26. Dezember 2005, 11:15 Uhr&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l442&quot; &gt;Zeile 442:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Zeile 442:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Benutzer:Lossy eX|Lossy eX]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Benutzer:Lossy eX|Lossy eX]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{TUTORIAL_NAVIGATION|&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;-&lt;/del&gt;|-}}&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{TUTORIAL_NAVIGATION| &lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;[[Tutorial Komponentenentwicklung]] &lt;/ins&gt;| &lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;[[Tutorial Software&lt;/ins&gt;-&lt;ins class=&quot;diffchange diffchange-inline&quot;&gt;Synthesizer]]&lt;/ins&gt;}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Kategorie:Tutorial|Multithreading]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;&amp;#160;&lt;/td&gt;&lt;td style=&quot;background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Kategorie:Tutorial|Multithreading]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>MyChaOS</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=11966&amp;oldid=prev</id>
		<title></title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Multithreading&amp;diff=11966&amp;oldid=prev"/>
				<updated>2005-10-29T16:11:26Z</updated>
		
		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;=Multithreading=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
In diesem (meinem ersten) Tutorial versuche ich euch etwas in das Mysterium der Threads einzuweihen und&lt;br /&gt;
ich werde versuchen euch die Leistungsfähigkeit und die Gefahren etwas näher zu bringen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Was ist ein Thread?==&lt;br /&gt;
&lt;br /&gt;
Als erstes sollten wir einmal klären was ein Thread überhaupt ist. &amp;lt;br&amp;gt;&lt;br /&gt;
Ein Thread ist die Möglichkeit mehrere Quellcodes zur &amp;quot;gleichen Zeit&amp;quot; ausführen zu können.&amp;lt;br&amp;gt;&lt;br /&gt;
Hier haben wir schon Trugschluss Nummer eins! In echt werden diese Quellen nicht zur gleichen Zeit ausgeführt.&lt;br /&gt;
Sie werden abwechselnd aufgerufen. Dies geschieht allerdings so schnell, dass man es mit bloßem Auge nicht sehen kann.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Nehmen wir mal an wir haben 2 Threads in einer Anwendung und beide führen große Berechnungen aus. &lt;br /&gt;
Dann wird es so aussehen, dass Thread 1 anfängt etwas zu berechnen und dann (nach wenigen Millisekunden) &lt;br /&gt;
wird er vom Betriebssystem unterbrochen und Thread 2 darf etwas rechnen. Dieser wird dann auch wieder unterbrochen und Thread 1 darf wieder.&lt;br /&gt;
So geht das weiter bis nichts zu berechnen mehr übrig ist.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Neben dem Multithreading gibt es noch das sogenannt Multiprocessing.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Unterschied zum Threading ist der, dass wir mehrere Anwendungen haben und somit auch vollkommen unterschiedliche Speicherbereiche.&amp;lt;br&amp;gt;&lt;br /&gt;
Das ist beim Multithreading nicht der Fall, da wir ja nur eine Anwendung haben. &lt;br /&gt;
Und aus den gleichen Speicherbereichen und den Unterbrechungen resultiert die Notwendigkeit, &lt;br /&gt;
dass wir die Threads untereinander synchronisieren müssen (siehe Abschnitt [[Tutorial_Multithreading#Synchronschwimmen|Synchronschwimmen]]).&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Der Richtigkeit halber sollte hier erwähnt werden, dass zu Beginn einer jeden Anwendung schon ein eigenen Thread verfügbar ist &lt;br /&gt;
(sonst würde sie ja nicht funktionieren). Dieser nennt sich VCL-Thread und arbeitet Windowsbotschaften (etc.) ab.&lt;br /&gt;
So gesehen ist er die Mutter für alles. Von diesem Thread sieht der Entwickler so gut wie gar nichts. Aber es ist da!&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wozu brauche ich Threads denn überhaupt?==&lt;br /&gt;
&lt;br /&gt;
Das typische Einsatzgebiet von Threads ist überall dort wo:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
#mehrere Quellen gleichzeitig ausgeführt werden müssen.&lt;br /&gt;
#:z.B.: Wenn man Spiel programmiert in dem im Hintergrund schon ein neuer Level geladen wird. Das beste Beispiel dafür ist Half-Life.&lt;br /&gt;
#:Am Ende eines Levels erscheint ein Schriftzug &amp;quot;Loading&amp;quot; und es ruckelt dann ein wenig. &lt;br /&gt;
#:Und genau zu diesem Zeitpunkt wird im Hintergrund ein neuer Level geladen. So hat man den Eindruck es handele sich dabei um ein riesiges Level.&lt;br /&gt;
#wo man auf Hardware warten muss (Modem)&lt;br /&gt;
#:z.B.: ein Webspider. Er lädt Webseiten auf die Festplatte. Dort muss die Anwendung größtenteils auf die Server warten.&lt;br /&gt;
#:An dieser Stelle haben Threads 2 große Vorteile:&lt;br /&gt;
#:# Solange auf den Server gewartet werden muss blockiert die Anwendung nicht (da nur der eine Thread wartet).&lt;br /&gt;
#:# Und der wohl größere Vorteil. Es wird ermöglicht, mehrere Dateien gleichzeitig herunter zu laden. &lt;br /&gt;
#:#:So kann man in kürzerer Zeit und effizienterer Nutzung der Internetanbindung (DSL, ...) eine Webseite herunter laden.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Das waren allerdings nur 2 Beispiele von vielen. Es ist der Kreativität eines Entwicklers freien Lauf gelassen.&amp;lt;br&amp;gt;&lt;br /&gt;
Desweiten ermöglichen es Threads auch mehrere im System vorhandene Prozessoren anzusprechen.&lt;br /&gt;
Und somit zum Beispiel auf dem einen Prozessor zu Rendern und auf dem anderen die notwendigen Berechnungen durchzuführen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Wie kann ich sie denn erstellen?==&lt;br /&gt;
&lt;br /&gt;
Das Erstellen eines Thread ist in Delphi wahnsinnig einfach. *eg* &amp;lt;br&amp;gt; &lt;br /&gt;
Das Einzige was wir tun müssen ist die Klasse TThread abzuleiten und die Methode Execute zu überschreiben.&amp;lt;br&amp;gt;&lt;br /&gt;
Wer keine Ahnung von Objekt orientiertem Programmieren (OOP) hat sollte sich an dieser Stelle erst einmal darüber schlau machen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;interface&lt;br /&gt;
&lt;br /&gt;
uses&lt;br /&gt;
  classes;&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  TMyOwnThread = class(Thread)&lt;br /&gt;
  protected&lt;br /&gt;
    procedure Execute; override;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
procedure TMyOwnThread.Execute;&lt;br /&gt;
begin&lt;br /&gt;
  // Führe hier irgendwelche Berechnungen aus.&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das war es. &amp;lt;br&amp;gt;&lt;br /&gt;
Ihr werdet euch jetzt Fragen was daran so kompliziert ist!&amp;lt;br&amp;gt;&lt;br /&gt;
Bisher noch nichts! Das Komplizierte kommt erst jetzt. &lt;br /&gt;
Wenn ihr zum Beispiel in dem Execute einen Fehler gemacht habt (Was man nie ausschließen kann) oder ihr versucht eine Datei zu öffnen die aber nicht existiert.&lt;br /&gt;
Dann wird von Delphi (zu Recht) eine Exception ausgelöst. Normalerweise wird diese von der Anwendung abgefangen und als Fehlermeldung (mit rotem Ausrufezeichen) ausgegeben.&lt;br /&gt;
Das hat bestimmt schon jeder einmal gesehen. Aber in einem Thread haben wir ein anderes Verhalten. Hier wird dieser Fehler spätestens vom Betriebssystem abgefangen. &lt;br /&gt;
Und das Betriebssystem terminiert zum Dank dann eure Anwendung mit dem Fehler &amp;quot;Unknow Software Error&amp;quot;. Das tollste an der Sache ist aber. &lt;br /&gt;
Sobald die Anwendung aus Delphi heraus gestartet wird fängt Delphi diesen Fehler ab. Allerdings liefert Delphi dann KEINEN Fehler. &lt;br /&gt;
Es kommt nicht einmal eine Warnung! Es kommt gar nichts! Die Anwendung läuft ohne Fehler weiter. &lt;br /&gt;
Und sobald sie außerhalb von Delphi gestartet wird, wird sie vom Betriebssystem abgeschossen.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Wie kann ich dem vorbeugen?&amp;lt;br&amp;gt;&lt;br /&gt;
Und zwar in dem ich die Exceptions abfange. Auch wenn ich sie dann einfach nur ignoriere (was natürlich dreckig wäre) aber abfangen muss ich sie.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TMyOwnThread.Execute;&lt;br /&gt;
begin&lt;br /&gt;
  try&lt;br /&gt;
    // Führe hier irgendwelche Berechnungen aus.&lt;br /&gt;
  except&lt;br /&gt;
    on e: exception do begin&lt;br /&gt;
      // mache hier irgendetwas mit dem Fehler.&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Soviel zur Vorbereitung. Jetzt wollen wir den Thread aber auch ausführen. &lt;br /&gt;
Dazu brauchen wir zu erst eine Methode in der wir diesen Thread erzeugen können. Nehmen wir mal das Event Form1.OnCreate.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure TForm1.FormCreate(Sender: TObject);&lt;br /&gt;
var&lt;br /&gt;
  Thread: TMyOwnThread;&lt;br /&gt;
begin&lt;br /&gt;
  Thread := TMyOwnThread.Create(True);&lt;br /&gt;
  // Der Parameter heißt CreateSuspended.&lt;br /&gt;
  // Er hat zur Folge wenn wir ein false übergeben,&lt;br /&gt;
  // dass der Thread sofort anfängt mit arbeiten.&lt;br /&gt;
  // meist haben wir ihm dann aber noch gar keine Daten übergeben.&lt;br /&gt;
  // also rufen wir ihm Suspended auf&lt;br /&gt;
&lt;br /&gt;
  Thread.FreeOnTerminate := True;&lt;br /&gt;
  // FreeOnTerminate bedeutet sobald der Thread die Procedure Execute&lt;br /&gt;
  // verlassen hat wird sein Speicher wieder von alleine Frei gegeben.&lt;br /&gt;
  // andernfalls müsste später im Programm Thread.Free aufgerufen werden.&lt;br /&gt;
&lt;br /&gt;
  Thread.Resume;&lt;br /&gt;
  // Falls der Thread suspended gestartet wurde sorgt dies dafür,&lt;br /&gt;
  // dass er anfängt mit arbeiten.&lt;br /&gt;
&lt;br /&gt;
  Thread.Suspend;&lt;br /&gt;
  // Dies sorgt dafür, dass die Arbeit des Threads pausiert wird.&lt;br /&gt;
  // Weiteführung durch Resume.&lt;br /&gt;
&lt;br /&gt;
  Thread.Terminate;&lt;br /&gt;
  // Hierbei handelt es sich nicht um eine Methode die dafür sorgt,&lt;br /&gt;
  // dass der Thread aufhört zu arbeiten. Sondern sie setzt eine Variable&lt;br /&gt;
  // (FTerminated) in der Basisklasse.&lt;br /&gt;
  // Ein Thread muss auf diese Methode selber reagieren.&lt;br /&gt;
  // Wenn in Execute Berechnungen in einer Schleife durchgeführt werden,&lt;br /&gt;
  // dann muss die Property Terminated abgefragt werden&lt;br /&gt;
  // und wenn diese gesetzt ist, dann sollte die arbeit&lt;br /&gt;
  // normal beendet werden und die Methode verlassen werden.&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das war es eigentlich schon soweit zum Thema Thread erstellen. Ach ja noch eines. &lt;br /&gt;
Der Thread ist ansonsten genau dasselbe wie jede andere Klasse auch. &lt;br /&gt;
Sprich er kann genau so erweitert werden wie das Form1 oder sonst irgendeine Klasse.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Synchronschwimmen==&lt;br /&gt;
(oder auch wo bin ich) ...&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Das wohl komplizierteste an Multithreading ist zu wissen in welchem Thread (Kontext) eine Methode aufgerufen wird &lt;br /&gt;
und wann bzw. was man sie synchronisieren oder sie schützen sollte.&lt;br /&gt;
In diesem Abschnitt versuche ich das euch einmal näher zu erklären.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Um schon einmal den wohl am häufigst gemachten Irrtum aus der Welt zu schaffen:&amp;lt;br&amp;gt;&lt;br /&gt;
Ein Thread existiert erst genau dann, wenn die Execute Methode aufgerufen wurde. &lt;br /&gt;
Und dort meine ich nicht, dass man irgendwo im Quelltext Thread.Execute stehen hat.&lt;br /&gt;
Nein ich meine den resultierenden Aufruf vom Betriebssystem auf Thread.Resume.&lt;br /&gt;
Da das bestimmt ein wenig unverständlich war hier mal ein paar Beispiele aus dem FormCreate (VCL-Thread):&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;Thread := Thread.Create(True);&lt;br /&gt;
// Der Konstructor wird aus dem VCL-Thread aufgerufen&lt;br /&gt;
// es existiert noch kein Thread!&lt;br /&gt;
&lt;br /&gt;
Thread.Resume;&lt;br /&gt;
// Hiermit wird der Thread angeworfen und sobald&lt;br /&gt;
// die erste Zeile von Execute aufgerufen&lt;br /&gt;
// wurde existiert der Thread&lt;br /&gt;
&lt;br /&gt;
Thread.Suspend;&lt;br /&gt;
// Es handelt sich zwar hier um eine Methode der Threadklasse&lt;br /&gt;
// allerdings wird sie im Kontext vom VCL-Thread aufgerufen.&lt;br /&gt;
// Der Thread wird hierbei aber vom Betriebssystem angehalten.&lt;br /&gt;
// Resume kann diesen dann jederzeit wieder starten.&lt;br /&gt;
&lt;br /&gt;
Thread.Terminate;&lt;br /&gt;
// Genau da Selbe wie bei Suspend allerdings wird er hierdurch&lt;br /&gt;
// nicht angehalten.&lt;br /&gt;
// sondern es wird die schon besprochene Variable gesetzt.&lt;br /&gt;
&lt;br /&gt;
Thread.Execute;&lt;br /&gt;
// Die Execute Methode wurde nicht vom Betriebsssytem aufgerufen&lt;br /&gt;
// und wird somit im Kontext vom VCL-Thread aufgerufen.&lt;br /&gt;
// Es existiert KEIN Thread.&lt;br /&gt;
&lt;br /&gt;
// Das funktioniert allerdings nur sofern diese als Public&lt;br /&gt;
// überschrieben wurde. Was natürlich nicht gemacht werden sollte!!!&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt mal ein Beispiel aus dem Thread.Execute:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;Thread.Terminate;&lt;br /&gt;
// Diese Methode wurde nun aus dem Kontext vom den Thread&lt;br /&gt;
// aufgerufen und setzt die bekannte Variable.&lt;br /&gt;
&lt;br /&gt;
Form1.Button1OnClick();&lt;br /&gt;
// Hierbei handelt es sich zwar um eine Methode aus dem VCL-Thread&lt;br /&gt;
// (Form1) aber sie wird im Kontext von unserem Thread aufgerufen.&lt;br /&gt;
// Es spielt überhaupt keine Rolle wie die Methode heißt oder&lt;br /&gt;
// was sie macht. Es könnte sich hierbei auch um einen Callback&lt;br /&gt;
// vom Thread handeln.&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Alles was aus dem Execute aufgerufen wird hat als Kontext diesen Thread!}}&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jetzt stellt sich natürlich die Frage was muss alles synchronisiert werden?&amp;lt;br&amp;gt;&lt;br /&gt;
Pauschal lässt sich nur sagen, alles was irgendwo von mehreren Threads (incl. VCL-Thread) geschrieben werden kann muss synchronisiert werden.&lt;br /&gt;
Ich erkläre euch das mal besser an einem kleinem Beispiel:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Nehmen wir einmal an wir haben einen Webspider. Dieser soll 200 Webseiten downloaden.&amp;lt;br&amp;gt;&lt;br /&gt;
Wir erstellen uns einen Thread dem ich die URL übergebe und der selbständig mit dem Laden anfängt.&lt;br /&gt;
Wenn dieser fertig ist dann sagt er dem VCL-Thread mittels eines Events, dass er fertig ist. Aussehen würde das so:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TBinFertig = procedure(const Content: String) of object;&lt;br /&gt;
&lt;br /&gt;
  TMyOwnThread = class(TThread)&lt;br /&gt;
  private&lt;br /&gt;
    FBinFertig: TBinFertig;&lt;br /&gt;
    procedure SyncBinFertig;&lt;br /&gt;
  public&lt;br /&gt;
    property BinFertig: TBinFertig read FBinFertig write FBinFertig;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
procedure TMyOwnThread.SyncBinFertig;&lt;br /&gt;
begin&lt;br /&gt;
  if Assigned(FBinFertig)&lt;br /&gt;
    then FBinFertig(DasIstDerInhaltDerWebseite);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TMyOwnThread.Execute;&lt;br /&gt;
begin&lt;br /&gt;
  try&lt;br /&gt;
    // Download der Seite ...&lt;br /&gt;
&lt;br /&gt;
    // Synchronisieren&lt;br /&gt;
    Synchronize(SyncBinFertig);&lt;br /&gt;
  except&lt;br /&gt;
    on e: exception do begin&lt;br /&gt;
      // mache hier irgendetwas mit dem Fehler.&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So lasst das Stück Quelle einmal auf euch wirken.&amp;lt;br&amp;gt;&lt;br /&gt;
Ich erkläre in der Zeit was genau wo passiert und warum das so aussieht.&lt;br /&gt;
TBinFertig ist die Definition einer Objektmethode.&lt;br /&gt;
Das ermöglicht es Proceduren als Variablen zu speichern.&lt;br /&gt;
Siehe Button.OnClick oder die ganzen anderen Events.&lt;br /&gt;
Dieser wird dann als Eigenschaft (Property) nach außen geführt.&lt;br /&gt;
Somit können andere Klassen darauf zugreifen.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
In dem Execute wird jetzt mit Hilfe von Synchronize die Methode SyncBinFertig aufgerufen.&lt;br /&gt;
Wir haben dort eine zusätzliche Methode weil Synchronize nur Proceduren ohne Parameter akzeptiert.&lt;br /&gt;
Was macht Synchronize? Synchronize sorgt dafür, dass der VCL-Thread die Methode SyncBinFertig aufruft.&lt;br /&gt;
Und wie ihr euch denken werdet ist somit der Kontext von unserem Thread auf den VCL-Thread umgeleitet worden.&lt;br /&gt;
Synchronize macht aber noch etwas. Und zwar wartet es so lange bis die Methode SyncBinFertig zu Ende ausgeführt wurde.&lt;br /&gt;
Das hat zu bedeuten, dass unser Thread für diesen Zeitraum stehen bleibt. Danach geht alles wie gewohnt weiter.&lt;br /&gt;
Allerdings muss man darauf achten, dass der VCL-Thread zu diesem Zeitpunkt nichts zu tun hat.&lt;br /&gt;
Das soll bedeuten sobald der VCL-Thread in einer Methode steckt (Button1OnClick) wird kein Synchronize abgearbeitet!&lt;br /&gt;
Das kann zu sogenannten Deadlocks führen. Dazu aber unten mehr.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Warum müssen wir an dieser Stelle synchronisieren?&lt;br /&gt;
Wir müssen an dieser Stelle nicht immer synchronisieren. Wir müssen nur dann synchronisieren, wenn wir das Ergebnis in einen,&lt;br /&gt;
vom einem Thread (VCL-Thread oder anderer) verwalteten Speicherbereich, schreiben wollen!&lt;br /&gt;
Hier einmal zwei Beispiele die das etwas veranschaulichen sollen:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel 1 in dem wir '''nicht''' synchronisieren müssen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure Form1.BinFertig(const Content: String);&lt;br /&gt;
var&lt;br /&gt;
  FS: TFileStream;&lt;br /&gt;
begin&lt;br /&gt;
  FS := TFileStream.Create(FileName, fmCreate);&lt;br /&gt;
  FS.Write(Content[1], Length(Content));&lt;br /&gt;
  FS.Free;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel 2 in dem wir synchronisieren müssen.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure Form1.BinFertig(const Content: String);&lt;br /&gt;
begin&lt;br /&gt;
  Form1.Buffer := Form1.Buffer + Content;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Warum müssen wir Beispiel 2 synchronisieren und Beispiel 1 nicht?&amp;lt;br&amp;gt;&lt;br /&gt;
Ihr erinnert euch bestimmt an das was ich oben gesagt hatte?&amp;lt;br&amp;gt;&lt;br /&gt;
Nein. Macht nichts. Und zwar sagt ich, dass Thread 1 mit seinen Berechnungen unterbrochen wird und Thread 2 etwas machen darf.&lt;br /&gt;
So was ist wenn jetzt 2 von den 5 Threads gleichzeitig fertig geworden sind?&lt;br /&gt;
Thread 1 ruft BinFertig auf. Diese Methode will nun den Content ihrer Seite an den bereits vorhandenen anhängen.&lt;br /&gt;
Der Thread ist zu 50% mit der Arbeit fertig und nun ist Thread 2 an der Reihe!&lt;br /&gt;
Auch er hängt jetzt ein bisschen was an den vorhandenen an. Jetzt die Frage was kommt im Endeffekt dabei raus?&lt;br /&gt;
Ich weiß es auch nicht! Ich schätze aber mal, dass entweder totaler Datenmüll oder ein Absturz dabei raus kommt.&lt;br /&gt;
Und genau aus diesem Grund muss hier synchronisiert werden.&lt;br /&gt;
So kann nur maximal 1 Thread etwas an dem Buffer anhängen und die anderen müssen warten!&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Beispiel 1 muss nicht synchronisiert werden, da die Daten auf die Platte geschrieben werden.&lt;br /&gt;
Es macht dort keinen Unterschieb ob der Thread unterbrochen wird oder nicht.&lt;br /&gt;
{{Hinweis|VORSICHT! Wenn jetzt die gesamten Threads aber mit ein und dem selben FileStream arbeiten dann muss auch synchronisiert werden.&lt;br /&gt;
Da dieser FileStream sozusagen ein und den selbe Speicherbereich darstellt!}}&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Ein anderer Fall in dem Synchronisiert werden muss ist, wenn ein Thread gerade etwas lesen möchte und ein anderer etwas genau dort hin schreiben will.&lt;br /&gt;
In diesem Fall kann genau das selbe passieren wie in Beispiel 2 wenn nicht synchronisiert wird.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Speicherbereiche schützen==&lt;br /&gt;
&lt;br /&gt;
Eine andere Möglichkeit etwas zu schützen sind sogenannte '''Critical Sections''' (zu gut Deutsch: kritische Bereiche).&amp;lt;br&amp;gt; &lt;br /&gt;
Der Buffer in Beispiel 2 wäre ein solcher Bereich. Critical Sections ermöglichen es dem Entwickler einen Bereich gegen andere Threads zu sichern.&lt;br /&gt;
Also Erstes brauchen wir eine Membervariable in Form1. Diese muss das z.B.: im OnCreate erzeugt werden:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;uses&lt;br /&gt;
  ..., SyncObjs;&lt;br /&gt;
&lt;br /&gt;
TForm1 = class(TForm)&lt;br /&gt;
  ...&lt;br /&gt;
private&lt;br /&gt;
  FBufferCritSect: TCriticalSection;&lt;br /&gt;
  ...&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anschließend sieht unser BinFertig so aus:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure Form1.BinFertig(const Content: String);&lt;br /&gt;
begin&lt;br /&gt;
  FBufferCritSect.Enter;&lt;br /&gt;
  Form1.Buffer := Form1.Buffer + Content;&lt;br /&gt;
  FBufferCritSect.Leave;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun brauchen wir unser BinFertig auch nicht mehr synchronisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
Warum den das jetzt?&amp;lt;br&amp;gt;&lt;br /&gt;
Die CriticalSection die wir eingesetzt haben würde dafür sorgen, dass maximal 1 Thread sich in dem Block zwischen Enter und Leave aufhalten würde.&lt;br /&gt;
Alle anderen müssten dann warten bis sie an der Reihe sind.&lt;br /&gt;
Dadurch, dass wir nicht mehr synchronisieren müssen, würde der Kontext wieder bei den einzelnen Thread bleiben.&lt;br /&gt;
Unser VCL-Thread würde also mit einer Critical Section nicht zu tun haben. (er würde Däumchen drehen) &lt;br /&gt;
Dafür könnte er sich aber voll und ganz um dem Rest kümmern können. &lt;br /&gt;
Um zu vermeiden, dass bei einem Fehler die Critical Section für immer und ewig verschlossen bleibt (Deadlock) sollte man einen Ressourcenschutzblock um sie herum errichten.&lt;br /&gt;
Das soll bedeuten. Auch im Fehlerfall würde eine gewisse Aktion IMMER ausgeführt werden. Unsere Exception wird dadurch aber nicht abgefangen!&lt;br /&gt;
Sie wird ganz normal weitergeleitet.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;procedure Form1.BinFertig(const Content: String);&lt;br /&gt;
begin&lt;br /&gt;
  FBufferCritSect.Enter;&lt;br /&gt;
  try&lt;br /&gt;
    Form1.Buffer := Form1.Buffer + Content;&lt;br /&gt;
  finally&lt;br /&gt;
    // Egal was auch passiert die Section würde immer verlassen werden&lt;br /&gt;
    // Sofern die Section und die Anwendung noch existieren, und&lt;br /&gt;
    // der Rechner noch Läuft. ;)&lt;br /&gt;
    FBufferCritSect.Leave;&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Was ist denn das schon wieder?==&lt;br /&gt;
&lt;br /&gt;
Was wäre das Leben wenn das bisher schon alle Probleme waren? Einfach langweilig ist weiß!&amp;lt;br&amp;gt;&lt;br /&gt;
Also hier noch einmal ein nicht unbedingt triviales Problem:&amp;lt;br&amp;gt; &lt;br /&gt;
Was ist passiert wenn meine Anwendung auf einmal ohne ehrsichtlich Grund stehen bleibt?&lt;br /&gt;
Also es tritt kein Fehler auf. Nein. Sie bleibt einfach stehe und ich kann nichts dagegen unternehmen.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Das was man sich dann eingefangen hat ist Deadlock. Das Programm wartet an 2 Stellen darauf, dass sich jeweils die andere fertig wird.&lt;br /&gt;
Ein hoffentlich einfaches Beispiel:&amp;lt;br&amp;gt;&lt;br /&gt;
Wir haben einen Thread der besitzt eine Methode. &lt;br /&gt;
In dieser Methode wartet er darauf, dass der Thread etwas ganz bestimmtes getan hat und kehrt dann zurück. &lt;br /&gt;
Wenn diese Methode jetzt aus dem VCL-Thread aufgerufen und in diesem Thread, in der Zeit wären der VCL-Thread auf das Rückkehren der Methode wartet,&lt;br /&gt;
ein Synchronize aufgerufen wird, dann ergibt das einen Deadlock. Die Erklärung ist einfach:&amp;lt;br&amp;gt; &lt;br /&gt;
Das Synchronize wartete ja darauf, dass der VCL-Thread es abarbeiten kann. Wenn dieser aber selber wartet, dann bleiben beide stehen.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Ein anderes Beispiel haben wir im Abschnitt darüber kennen gelernt. &lt;br /&gt;
Und zwar wenn durch einen Fehler die Critical Section nicht wieder geöffnet wurde.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Prioritäten==&lt;br /&gt;
&lt;br /&gt;
Das Setzen von Threadprioritäten geschieht über die Eigenschaft Priority eines Threads.&amp;lt;br&amp;gt;&lt;br /&gt;
Was ist das Hinterlistige an den Prioritäten? Oder anders gesagt worauf sollte man achten, wenn man Prioritäten einstellt?&amp;lt;br&amp;gt;&lt;br /&gt;
Standardmäßig wird von jedem Thread oder Prozess die Priorität Normal verwendet. &lt;br /&gt;
Wenn ich nun aber einen Thread habe der eine höhere Priorität erhalten soll dann muss ich darauf achten,&lt;br /&gt;
dass er noch genügend Ressourcen für die Anderen übrig lässt. Das soll mal an einem kleinen Beispiel erläutert werden:&amp;lt;br&amp;gt;&lt;br /&gt;
Wir haben einen Thread der besonders wichtige Berechnungen durchführt. Diese sollen sehr zeitkritisch also mit hoher Priorität abgearbeitet werden.&lt;br /&gt;
In dem Execute muss ich also nachschauen ob ich eine Berechnung vorliegen habe:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;while (not Terminated) do begin&lt;br /&gt;
  if (BerechnungDa) then begin&lt;br /&gt;
    // berechne&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An und für sich wäre das ja schon die Lösung des Problems. Allerdings dadurch, dass ich permanent nachschaue ob ich eine Berechnung da habe,&lt;br /&gt;
würde dieser Thread so viel an CPU klauen, dass für die anderen nichts mehr übrig bliebe.&lt;br /&gt;
Wenn ich die Priorität auf Echtzeit gesetzt habe kann es sogar sein, dass Windows stehen bleibt und sich nur noch auf das konzentriert.&lt;br /&gt;
Eine Lösung für dieses Problem wäre wenn ich nur ein paar mal in der Sekunde nachschauen würde:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;while (not Terminated) do begin&lt;br /&gt;
  if (BerechnungDa) then begin&lt;br /&gt;
    // berechne&lt;br /&gt;
  end else begin&lt;br /&gt;
    sleep(10);&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das würde dafür sorgen, dass nur 100mal in der Sekunde abgefragt werden würde. &lt;br /&gt;
Diese Auflösung würde schon für die meisten Sachen vollkommen ausreichen aber wir können noch einen drauf setzen. &lt;br /&gt;
Das hätte dann eine noch höhere Auflösung bei weniger Aufwand (Abfragen in der Sekunde) von unserer Seite. &lt;br /&gt;
Das Ganze würde dann mit Hilfe eines Events arbeiten. Events sind in der Unit SyncObjs deklariert.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;Event := TEvent.Create(nil, true, false, '');&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So wird ein Event erzeugt. Der erste Parameter ist ein Pointer auf ein SecureAttribut. &lt;br /&gt;
Das ist in den meisten Fällen (bei mir immer ;) ) nil. Viel interessante sind die anderen drei. &lt;br /&gt;
Der zweite Parameter gibt an ob das Event sich von alleine wieder zurücksetzen kann. &lt;br /&gt;
Der Vorteil davon, jedes Mal wenn dieses Event ausgelöst wird kann immer nur einer der darauf wartenden Parteien (Threads) das Signal bekommen.&lt;br /&gt;
Der Dritte ist der Initialisierungsstatus. Sprich ob es zu Begin gleich gesetzt ist oder lieber doch nicht. &lt;br /&gt;
Der Vierte ist wieder sehr geil. Dieser ist der Name des Events. Warum zu Teufel brauch ein Event einen Namen? &lt;br /&gt;
Ganz einfach, wenn es von mehren Anwendungen gleichzeitig abgefragt bzw. gesetzt werden soll dann muss es ja eindeutig identifizierbar sein. &lt;br /&gt;
Und genau das macht der Name. Ihr erzeugt euch zwei Events mit dem Selben Namen und schon könnt ihr andere Anwendungen damit triggern. :) &lt;br /&gt;
Aber wieder zurück zum Thema. So würde unsere Quelle mit einem Event ausschauen:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pascal&amp;gt;while (not Terminated) do begin&lt;br /&gt;
  if (Event.WaitFor(100) = wrSignaled) then begin&lt;br /&gt;
    // Sofern sich das Event nicht von alleine zurücksetzt müssen wir noch&lt;br /&gt;
    // Event.ResetEvent aufrufen.&lt;br /&gt;
&lt;br /&gt;
    // Berechne was&lt;br /&gt;
  end;&lt;br /&gt;
end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Methode die uns normalerweise die Berechnung übergeben würde müssen wir nur noch das Event auslösen (Event.SetEvent) und schon klappt alles.&lt;br /&gt;
Was passiert bei WaitFor? WaitFor ist so konzipiert, dass es 100 Millisekunden warten würde und wenn das Event immer noch nicht ausgelöst wurde,&lt;br /&gt;
dann würde es mit wrTimeOut zurückkommen. Wenn dieses Event jetzt allerdings nach 10 Millisekunden schon ausgelöst wurde,&lt;br /&gt;
dann wartet WaitFor logischerweise nicht noch 90 Millisekunden. &lt;br /&gt;
Nein. Es kehrt sofort wieder zurück und als Rückgabewert würden wir wrSignaled bekommen. &lt;br /&gt;
Warum habe ich jetzt allerdings 100Millisekunden verwendet und nicht etwa unendlich (INFINITE) oder 15 Minuten?&lt;br /&gt;
Na weil wir ja sonst nicht wüssten wann unser Thread terminiert wurde! So wird 10 mal in der Sekunde abgeprüft ob er terminiert wurde.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Schlusswort==&lt;br /&gt;
&lt;br /&gt;
Wenn man sich einen Thread erzeugen will der in einem Fenster OpenGL rendert, dann darf (sollte) man dort so gut wie gar nichts synchronisieren.&lt;br /&gt;
Allerdings wenn man etwas synchronisiert, dann MUSS alles synchronisiert werden. Also ich denke jetzt an das Initialisieren, das Rendern und Löschen des Renderkontext.&lt;br /&gt;
Und wenn man alles synchronisiert, dann kann man auch komplett auf den Thread verzichten. Weil dadurch alles im VCL-Thread ausgeführt wird.&lt;br /&gt;
Und das ist ja eigentlich nicht Sinn und Zweck davon.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Also Merke! Nur das Notwendigste synchronisieren oder versuchen ganz auf den Thread zu verzichten.&lt;br /&gt;
Und das Notwendigste ist alles das wo sich Überschneidungen beim Schreiben ergeben können. &lt;br /&gt;
Lesen alleine ist ungefährlich, weil dort ja keine Daten verändert werden.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Sinne.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Euer&amp;lt;br&amp;gt;&lt;br /&gt;
[[Benutzer:Lossy eX|Lossy eX]]&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|-}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Multithreading]]&lt;/div&gt;</summary>
		<author><name>Flash</name></author>	</entry>

	</feed>