Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
1 Einführung
2 Grundlagen der Sprachsyntax
3 Klassendesign
4 Weitere Datentypen
5 Multithreading
6 Collections und LINQ
7 Eingabe und Ausgabe
8 Anwendungen: Struktur und Installation
9 Code erstellen und debuggen
10 Einige Basisklassen
11 Windows-Anwendungen erstellen
12 Die wichtigsten Steuerelemente
13 Tastatur- und Mausereignisse
14 MDI-Anwendungen
15 Grafiken mit GDI+
16 Drucken
17 Entwickeln von Steuerelementen
18 Programmiertechniken
19 WPF – Grundlagen
20 Layoutcontainer
21 WPF-Steuerelemente
22 Konzepte von WPF
23 Datenbankverbindung mit ADO.NET
24 Datenbankabfragen mit ADO.NET
25 DataAdapter
26 Offline mit DataSet
27 Datenbanken aktualisieren
28 Stark typisierte DataSets
A Anhang: Einige Übersichten
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual Basic 2008 von Andreas Kuehnel, Stephan Leibbrandt
Das umfassende Handbuch
Buch: Visual Basic 2008

Visual Basic 2008
3., aktualisierte und erweiterte Auflage, geb., mit DVD
1.323 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1171-0
Pfeil 5 Multithreading
Pfeil 5.1 Start eines Threads
Pfeil 5.1.1 Parameterloser Start
Pfeil 5.1.2 Start mit Parameter
Pfeil 5.1.3 Hintergrundthreads
Pfeil 5.1.4 Threadeigenschaften
Pfeil 5.2 Zusammenspiel
Pfeil 5.2.1 Priorität
Pfeil 5.2.2 Warten mit Sleep
Pfeil 5.2.3 Unterbrechen mit Interrupt
Pfeil 5.2.4 Abbruch mit Abort
Pfeil 5.2.5 Warten mit Join
Pfeil 5.2.6 Warten erzwingen mit Suspend
Pfeil 5.2.7 Threadzustände
Pfeil 5.2.8 Die Klasse Thread
Pfeil 5.3 Gesicherter Datenaustausch
Pfeil 5.3.1 Objekte sperren mit Monitor
Pfeil 5.3.2 Codebereiche mit SyncLock sperren
Pfeil 5.3.3 Sperrung mit Zustand
Pfeil 5.3.4 Atomare Operationen
Pfeil 5.3.5 Attributgesteuerte Synchronisation
Pfeil 5.4 Asynchrone Methodenaufrufe
Pfeil 5.4.1 Aufruf
Pfeil 5.4.2 Rückruf
Pfeil 5.4.3 Zustand
Pfeil 5.4.4 Rückgabe
Pfeil 5.4.5 ByRef-Parameter
Pfeil 5.5 Threadpools

Dieses Kapitel widmet sich dem Zusammenspiel gleichzeitig ablaufender Programme. Insbesondere der gemeinsame Zugriff auf dieselben Daten muss geregelt werden.

5 Multithreading

In diesem Kapitel gehe ich auf den Themenkreis ein, der mit dem letzten verbliebenen Schlüsselwort von Visual Basic, SyncLock, zusammenhängt (die LINQ-spezifischen Wörter im nächsten Kapitel sind keine echten Schlüsselwörter). Bevor wir es einsetzen können, muss erst dieser Themenkreis erläutert werden. In Abschnitt 3.9.4, »Asynchrone Aufrufe«, haben wir bereits erste Schritte unternommen, um mehrere Aktionen parallel zu bearbeiten. Dieser Abschnitt beschäftigt sich nun mit der geregelten Zusammenarbeit der parallel ablaufenden Aktivitäten. Jede wird in einem sogenannten Thread (englisch: Faden) verwaltet. Er stellt die Schnittstelle zur Verfügung, damit das Betriebssystem einem Programmteil Hardware zuweisen (oder entziehen) kann. Jede Anwendung enthält einen oder mehrere Threads. Sind es mehrere, spricht man von Multithreading.

Für die hier beschriebenen Prinzipien spielt es keine Rolle, ob die verschiedenen Programmteile auf verschiedenen Prozessoren laufen oder nur auf einem einzelnen – in einem Restaurant ist es Ihnen ja auch einerlei, wer die leckere Mahlzeit kocht. In der Praxis können sich dadurch Unterschiede in der Laufzeit ergeben, dass bei mehreren Aktionen auf demselben Prozessor eine »parallele« Ausführung dadurch simuliert wird, dass zwischen ihnen schnell hin und her geschaltet wird. Koordiniert wird der Vorgang durch ein Programm des Betriebssystems namens Scheduler. Nach jedem Schaltvorgang wird der Prozessor eine kurze Zeit für einen Programmteil reserviert. Die Zeiten für die Umschaltung machen sich in der Praxis nur dann bemerkbar, wenn zwischen extrem vielen kleinen Einheiten sehr oft umgeschaltet werden muss. Außer der Ausführungszeit gibt es keine Effekte durch unterschiedliche Prozessorzahlen. Selbst der gleichzeitige Zugriff von zwei Prozessoren auf dieselben Daten ist nicht wirklich unterschiedlich, da die Umschaltung ja auch während eines Datenzugriffs erfolgen kann und daher der Datenzugriff sowieso genau geregelt werden muss.


Hinweis
Mit dem Ende des letzten Threads einer Anwendung wird diese auch beendet.


Da die Verwendung mehrerer Threads Ressourcen verbraucht und die Umschaltung zwischen den Threads auch ein wenig Zeit kostet, sollten Sie nicht jede kleine Aufgabe in einen eigenen Thread verpacken. Außerdem wird die Fehlersuche in einer Anwendung mit mehreren Threads schnell aufwendig. Es gibt aber auch gute Gründe dafür, einen neuen Thread für eine Aufgabe zu nutzen:

  • Der normale Programmfluss hat mit der Aufgabe nichts zu tun, zum Beispiel das Abspielen von Hintergrundmusik.
  • Etwas muss vorrangig ausgeführt werden, zum Beispiel die Maussteuerung.
  • Eine aufwendige Aufgabe soll andere Programmteile nicht blockieren, zum Beispiel das Laden eines Videos.
  • Eine Aktivität soll von außen kontrollierbar sein, zum Beispiel um sie abzubrechen.

In den folgenden Abschnitten erläutere ich zuerst, wie ein Thread gestartet wird und welche Zustände er annehmen kann. Dann widme ich mich dem Zusammenspiel mit anderen Threads und dem Datenaustausch zwischen verschiedenen Threads. Der Aufruf parallel ablaufender Methoden und eine kurze Einführung in Threadpools bilden den Abschluss.


Rheinwerk Computing - Zum Seitenanfang

5.1 Start eines Threads Zur nächsten ÜberschriftZur vorigen Überschrift

Nur Programmteile, die einem Thread zugeordnet sind, können ausgeführt werden, da der Thread die Schnittstelle zum Betriebssystem darstellt und dieses die volle Kontrolle über alle Prozesse haben muss. Bisher haben Sie in den meisten Programmen nichts davon gemerkt, da der Start des Hauptthreads zusammen mit dem Start der Anwendung erfolgt ist. Hier starten wir Programmteile explizit in einem anderen als dem Hauptthread. Damit ein Programmteil von den anderen losgelöst gestartet werden kann, müssen zwei Schritte erfolgen:

  • Ein Objekt vom Typ Thread muss instanziiert werden.
  • Die Methode Start() dieses Objekts startet den Programmteil.

Alle Konstruktoren von Thread erwarten als ersten Parameter die Adresse einer Methode, die in einem Delegate gekapselt ist (siehe Abschnitt 3.9.1, »Funktionszeiger: Delegate«). Alle diese Delegates haben keinen Rückgabewert. In einem optionalen zweiten Parameter können Sie die Maximalgröße des Stacks festlegen (ab Windows XP). Neben der Verwaltungsinformation für sämtliche Methodenaufrufe werden auf dem Stack auch alle lokalen Variablen abgelegt. Wenn diese in Ihren Programmen viel Speicher belegen oder Sie viel Gebrauch von Rekursion machen, kann es notwendig sein, die Standardgröße des Stacks von 1 MB zu erhöhen. Sie sollten aber nicht zu großzügig Platz reservieren.


Hinweis
Ein einmal beendeter Thread kann nicht wieder gestartet werden.



Rheinwerk Computing - Zum Seitenanfang

5.1.1 Parameterloser Start Zur nächsten ÜberschriftZur vorigen Überschrift

Die einfachste Art, eine unabhängige Aktivität zu starten, verwendet keine Parameter bei deren Start.


Public NotInheritable Delegate Sub ThreadStart()

Das folgende Codefragment definiert eine Methode zum Ausdruck von Zeichen. Durch die Inkrementierung der klassengebundenen Variablen no wird jeder Aufruf ein anderes Zeichen ausgeben. Dies ermöglicht es uns, verschiedene Aufrufe zu unterscheiden. Die Methode wird sowohl über die Methode Start() eines neu erstellten Threads gestartet als auch direkt vom Hauptthread aus. Die erste Variante leiert den Start nur an. Die Abarbeitung erfolgt in einem anderen Thread, sodass der Aufruf Start() fast keine Zeit benötigt und mit der Programmausführung fortgefahren werden kann. Es laufen also zwei Versionen der Methode Druck() in unterschiedlichen Threads, die mit Console.Write() in dasselbe Ausgabefenster schreiben.


'...\Multitasking\Start\Parameterlos.vb

Option Strict On 
Imports System.Threading 
Namespace Multitasking 
  Module Parameterlos 
    Dim no As Integer = 0 
    Sub Druck() 
      no += 1 
      Dim z As Char = ChrW(41 + no) 
      For no As Integer = 0 To 200 
        Console.Write(z) 
      Next 
    End Sub

    Sub Test() 
      Dim start As New ThreadStart(AddressOf Druck) 
      Dim einheit As New Thread(start) 
      einheit.Start() 
      Druck() 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt, wie beide Threads abwechselnd zum Zuge kommen. Die Größe und Anzahl der Abschnitte sowie deren Reihenfolge im Ausdruck ist nicht festgelegt. Jeder neue Lauf des Programms kann ein neues Muster erzeugen. Sollten bei Ihnen die Pluszeichen immer nach den Sternen erscheinen, ist Ihr Rechner »zu« schnell, und Sie sollten den Schleifenzähler größer als 200 wählen. So erzwingen Sie eine Ausführungszeit, die größer als die Zeiteinheit ist, in denen das Betriebssystem einen Thread jeweils rechnen lässt.

****************************+++++++++++++++++++++++++++++++++++++++++++++++ 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
++++*********************************************************************** 
*************************************************************************** 
***************************

Diese Unvorhersagbarkeit der Ausgabe zeigt auch das Hauptproblem beim Multithreading: Es laufen mehrere Aktionen parallel, die sich ohne Weiteres ins Gehege kommen können.


Rheinwerk Computing - Zum Seitenanfang

5.1.2 Start mit Parameter Zur nächsten ÜberschriftZur vorigen Überschrift

Beim vorigen Beispiel war die Implementierung zur Unterscheidung der Threads etwas unbeholfen. Leichter wird es, wenn dem Thread beim Start ein Parameter mitgegeben werden kann. Dazu akzeptiert ein weiterer Konstruktor der Klasse Thread ein anderes Delegate als ersten Parameter:


Public NotInheritable Delegate Sub ParameterizedThreadStart(obj As Object)

Damit darf die Methode Druck() nun einen Parameter haben. Im folgenden Codefragment übergeben wir als Objekte zwei verschiedene Zahlen. Die Ausgabe ist qualitativ dieselbe wie im parameterlosen Fall.


'...\ Multitasking\Start\Parameter.vb

Option Strict On 
Imports System.Threading 
Namespace Multitasking 
  Module Parameter 
    Sub Druck(ByVal z As Object) 
      For no As Integer = 0 To 200 
        Console.Write(z) 
      Next 
    End Sub

    Sub Test() 
      Dim start As New ParameterizedThreadStart(AddressOf Druck) 
      Dim einheit As New Thread(start) 
      'kurz: Dim einheit As New Thread(AddressOf Druck) 
      einheit.Start(1) 
      Druck(2) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Hinweis
Vergessen Sie, einen Parameter an Start() zu übergeben, wird der Wert Nothing übergeben.



Rheinwerk Computing - Zum Seitenanfang

5.1.3 Hintergrundthreads Zur nächsten ÜberschriftZur vorigen Überschrift

.NET unterscheidet Vorder- und Hintergrundthreads. Wie der Name vermuten lässt, sind Letztere nicht zur direkten Kommunikation mit dem Benutzer ausgelegt, sondern arbeiten im Verborgenen. Daher ist die Lebensdauer einer Anwendung unabhängig von Hintergrundthreads. Egal wie viele davon noch laufen, mit dem Ende des letzten Vordergrundthreads wird auch die Anwendung beendet. Die Eigenschaft IsBackground legt fest, ob ein Thread im Hintergrund läuft. Im nächsten Codefragment wird in einem Hintergrundthread die Schleife in Druck() neunmal durchlaufen und im Hauptthread, der immer ein Vordergrundthread ist, zweimal. Die Schleife wird durch den Aufruf von Sleep() künstlich um eine Sekunde verzögert, damit Sie den Programmlauf leichter am Bildschirm verfolgen können. Dies ist wichtig, weil das Programm endet, ohne das Konsolenfenster offen zu halten. Die Methode Sleep() wird in Abschnitt 5.2, »Zusammenspiel«, genauer erläutert.


'...\ Multitasking\Start\Hintergrund.vb

Option Strict On 
Imports System.Threading 
Namespace Multitasking 
  Module Hintergrund 
    Sub Druck(ByVal z As Object) 
      For no As Integer = 0 To CType(z, Integer) 
        Console.Write(z) : Thread.Sleep(1000) 
      Next 
      Console.WriteLine("**") 
    End Sub

    Sub Test() 
      Dim einheit As New Thread(AddressOf Druck) 
      einheit.IsBackground = True 
      einheit.Start(9)             'Hintergrund : 9 Schleifendurchläufe 
      Druck(2)                     'Vordergrund : 2 Schleifendurchläufe 
    End Sub 
  End Module 
End Namespace

Hinweis
Mit ReadLine() am Programmende wird der Vordergrundthread am Leben erhalten, und der Effekt ist nicht zu sehen.


Einige Details in den Unterschieden von Vorder- und Hintergrundprozess sind betriebssystemabhängig. Auf einem Desktopbetriebssystem läuft ein Hintergrundprozess in der Regel langsamer als ein Vordergrundprozess, und die zugeteilten Zeitscheiben sind kürzer. Auf einem Serverbetriebssystem ist es umgekehrt.


Rheinwerk Computing - Zum Seitenanfang

5.1.4 Threadeigenschaften topZur vorigen Überschrift

Jeder Thread hat auch ein paar Eigenschaften, von denen ich hier einige herausgreife. Die vollständige Liste ist in Abschnitt 5.2.8, »Die Klasse Thread«, abgedruckt. Die klassengebundene Eigenschaft CurrentThread liefert eine Referenz auf den Thread, der die Anweisung gerade ausführt. Somit haben Sie die Möglichkeit, eine Referenz auf den Hauptthread einer Anwendung zu erhalten. Bei der Fehlersuche hilft die Benennung durch Name. Das folgende Codefragment zeigt diese Eigenschaften im Einsatz.


'...\ Multitasking\Start\Eigenschaften.vb

Option Strict On 
Imports System.Threading 
Namespace Multitasking 
  Module Eigenschaften 
    Sub Test() 
      Dim th As Thread = Thread.CurrentThread 
      Console.WriteLine("Hauptthread hat die ID {0} und den Namen ""{1}""", _ 
                        th.ManagedThreadId, th.Name) 
      th.Name = "Haupt" 
      Console.WriteLine("Thread {0} verwendet die Ländereinstellung {1}", _ 
                        th.Name, th.CurrentCulture) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Sowohl die ID als auch die Ländereinstellung können bei Ihnen andere Werte haben.

Hauptthread hat die ID 9 und den Namen "" 
Thread Haupt verwendet die Ländereinstellung en-US


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual Basic 2008
Visual Basic 2008
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Visual Basic 2012






 Visual Basic 2012


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern