C # - Multithreading
EIN threadist definiert als der Ausführungspfad eines Programms. Jeder Thread definiert einen eindeutigen Kontrollfluss. Wenn Ihre Anwendung komplizierte und zeitaufwändige Vorgänge umfasst, ist es häufig hilfreich, unterschiedliche Ausführungspfade oder Threads festzulegen, wobei jeder Thread einen bestimmten Job ausführt.
Themen sind lightweight processes. Ein häufiges Beispiel für die Verwendung von Threads ist die Implementierung der gleichzeitigen Programmierung durch moderne Betriebssysteme. Die Verwendung von Threads spart Verschwendung des CPU-Zyklus und erhöht die Effizienz einer Anwendung.
Bisher haben wir die Programme geschrieben, in denen ein einzelner Thread als einzelner Prozess ausgeführt wird, der die laufende Instanz der Anwendung ist. Auf diese Weise kann die Anwendung jedoch jeweils einen Job ausführen. Damit mehr als eine Aufgabe gleichzeitig ausgeführt wird, kann sie in kleinere Threads unterteilt werden.
Thread-Lebenszyklus
Der Lebenszyklus eines Threads beginnt, wenn ein Objekt der System.Threading.Thread-Klasse erstellt wird, und endet, wenn der Thread beendet wird oder die Ausführung abgeschlossen ist.
Es folgen die verschiedenen Zustände im Lebenszyklus eines Threads -
The Unstarted State - In diesem Fall wird die Instanz des Threads erstellt, die Start-Methode wird jedoch nicht aufgerufen.
The Ready State - Es ist die Situation, in der der Thread betriebsbereit ist und auf den CPU-Zyklus wartet.
The Not Runnable State - Ein Thread ist nicht ausführbar, wenn
- Die Schlafmethode wurde aufgerufen
- Die Wartemethode wurde aufgerufen
- Durch E / A-Vorgänge blockiert
The Dead State - Dies ist die Situation, in der der Thread die Ausführung abschließt oder abgebrochen wird.
Der Hauptfaden
In C # wird die System.Threading.ThreadKlasse wird zum Arbeiten mit Threads verwendet. Es ermöglicht das Erstellen und Zugreifen auf einzelne Threads in einer Multithread-Anwendung. Der erste Thread, der in einem Prozess ausgeführt wird, heißtmain Faden.
Wenn ein C # -Programm ausgeführt wird, wird der Hauptthread automatisch erstellt. Die mit dem erstellten ThreadsThreadKlasse werden die untergeordneten Threads des Hauptthreads genannt. Sie können mit dem auf einen Thread zugreifenCurrentThread Eigenschaft der Thread-Klasse.
Das folgende Programm demonstriert die Ausführung des Hauptthreads -
using System;
using System.Threading;
namespace MultithreadingApplication {
class MainThreadProgram {
static void Main(string[] args) {
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:
This is MainThread
Eigenschaften und Methoden der Thread-Klasse
Die folgende Tabelle zeigt einige der am häufigsten verwendeten properties des Thread Klasse -
Sr.Nr. | Objektbeschreibung |
---|---|
1 | CurrentContext Ruft den aktuellen Kontext ab, in dem der Thread ausgeführt wird. |
2 | CurrentCulture Ruft die Kultur für den aktuellen Thread ab oder legt diese fest. |
3 | CurrentPrinciple Ruft das aktuelle Prinzip des Threads ab oder legt es fest (für rollenbasierte Sicherheit). |
4 | CurrentThread Ruft den aktuell ausgeführten Thread ab. |
5 | CurrentUICulture Ruft die aktuelle Kultur ab oder legt diese fest, die vom Ressourcenmanager zum Nachschlagen kulturspezifischer Ressourcen zur Laufzeit verwendet wird. |
6 | ExecutionContext Ruft ein ExecutionContext-Objekt ab, das Informationen zu den verschiedenen Kontexten des aktuellen Threads enthält. |
7 | IsAlive Ruft einen Wert ab, der den Ausführungsstatus des aktuellen Threads angibt. |
8 | IsBackground Ruft einen Wert ab oder legt einen Wert fest, der angibt, ob ein Thread ein Hintergrundthread ist oder nicht. |
9 | IsThreadPoolThread Ruft einen Wert ab, der angibt, ob ein Thread zum verwalteten Thread-Pool gehört oder nicht. |
10 | ManagedThreadId Ruft eine eindeutige Kennung für den aktuell verwalteten Thread ab. |
11 | Name Ruft den Namen des Threads ab oder legt diesen fest. |
12 | Priority Ruft einen Wert ab oder legt einen Wert fest, der die Planungspriorität eines Threads angibt. |
13 | ThreadState Ruft einen Wert ab, der die Status des aktuellen Threads enthält. |
Die folgende Tabelle zeigt einige der am häufigsten verwendeten methods des Thread Klasse -
Sr.Nr. | Methode & Beschreibung |
---|---|
1 | public void Abort() Löst eine ThreadAbortException in dem Thread aus, in dem sie aufgerufen wird, um den Vorgang zum Beenden des Threads zu starten. Das Aufrufen dieser Methode beendet normalerweise den Thread. |
2 | public static LocalDataStoreSlot AllocateDataSlot() Weist allen Threads einen unbenannten Datensteckplatz zu. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
3 | public static LocalDataStoreSlot AllocateNamedDataSlot(string name) Weist allen Threads einen benannten Datensteckplatz zu. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
4 | public static void BeginCriticalRegion() Benachrichtigt einen Host, dass die Ausführung im Begriff ist, einen Codebereich einzugeben, in dem die Auswirkungen eines Thread-Abbruchs oder einer nicht behandelten Ausnahme andere Aufgaben in der Anwendungsdomäne gefährden können. |
5 | public static void BeginThreadAffinity() Benachrichtigt einen Host, dass verwalteter Code im Begriff ist, Anweisungen auszuführen, die von der Identität des aktuellen physischen Betriebssystem-Threads abhängen. |
6 | public static void EndCriticalRegion() Benachrichtigt einen Host, dass die Ausführung im Begriff ist, einen Codebereich einzugeben, in dem die Auswirkungen eines Thread-Abbruchs oder einer nicht behandelten Ausnahme auf die aktuelle Aufgabe beschränkt sind. |
7 | public static void EndThreadAffinity() Benachrichtigt einen Host, dass der verwaltete Code die Ausführung von Anweisungen beendet hat, die von der Identität des aktuellen physischen Betriebssystem-Threads abhängen. |
8 | public static void FreeNamedDataSlot(string name) Beseitigt die Zuordnung zwischen einem Namen und einem Steckplatz für alle Threads im Prozess. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
9 | public static Object GetData(LocalDataStoreSlot slot) Ruft den Wert aus dem angegebenen Steckplatz im aktuellen Thread innerhalb der aktuellen Domäne des aktuellen Threads ab. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
10 | public static AppDomain GetDomain() Gibt die aktuelle Domäne zurück, in der der aktuelle Thread ausgeführt wird. |
11 | public static AppDomain GetDomainID() Gibt eine eindeutige Anwendungsdomänenkennung zurück |
12 | public static LocalDataStoreSlot GetNamedDataSlot(string name) Sucht nach einem benannten Datensteckplatz. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
13 | public void Interrupt() Unterbricht einen Thread, der sich im Thread-Status WaitSleepJoin befindet. |
14 | public void Join() Blockiert den aufrufenden Thread, bis ein Thread beendet wird, während weiterhin Standard-COM- und SendMessage-Pumpvorgänge ausgeführt werden. Diese Methode hat verschiedene überladene Formen. |
15 | public static void MemoryBarrier() Synchronisiert den Speicherzugriff wie folgt: Der Prozessor, der den aktuellen Thread ausführt, kann Anweisungen nicht so neu anordnen, dass Speicherzugriffe vor dem Aufruf von MemoryBarrier nach Speicherzugriffen nach dem Aufruf von MemoryBarrier ausgeführt werden. |
16 | public static void ResetAbort() Bricht einen für den aktuellen Thread angeforderten Abbruch ab. |
17 | public static void SetData(LocalDataStoreSlot slot, Object data) Legt die Daten im angegebenen Steckplatz des aktuell ausgeführten Threads für die aktuelle Domäne dieses Threads fest. Verwenden Sie für eine bessere Leistung stattdessen Felder, die mit dem ThreadStaticAttribute-Attribut gekennzeichnet sind. |
18 | public void Start() Startet einen Thread. |
19 | public static void Sleep(int millisecondsTimeout) Lässt den Thread für einen bestimmten Zeitraum pausieren. |
20 | public static void SpinWait(int iterations) Bewirkt, dass ein Thread so oft wartet, wie durch den Parameter iterations definiert |
21 | public static byte VolatileRead(ref byte address) public static double VolatileRead(ref double address) public static int VolatileRead(ref int address) public static Object VolatileRead(ref Object address) Liest den Wert eines Feldes. Der Wert ist der letzte, den ein Prozessor in einem Computer geschrieben hat, unabhängig von der Anzahl der Prozessoren oder dem Status des Prozessor-Cache. Diese Methode hat verschiedene überladene Formen. Nur einige sind oben angegeben. |
22 | public static void VolatileWrite(ref byte address,byte value) public static void VolatileWrite(ref double address, double value) public static void VolatileWrite(ref int address, int value) public static void VolatileWrite(ref Object address, Object value) Schreibt sofort einen Wert in ein Feld, sodass der Wert für alle Prozessoren im Computer sichtbar ist. Diese Methode hat verschiedene überladene Formen. Nur einige sind oben angegeben. |
23 | public static bool Yield() Bewirkt, dass der aufrufende Thread die Ausführung für einen anderen Thread ermöglicht, der auf dem aktuellen Prozessor ausgeführt werden kann. Das Betriebssystem wählt den Thread aus, dem er nachgeben soll. |
Threads erstellen
Threads werden durch Erweitern der Thread-Klasse erstellt. Die erweiterte Thread-Klasse ruft dann die aufStart() Methode zum Starten der Ausführung des untergeordneten Threads.
Das folgende Programm demonstriert das Konzept -
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:
In Main: Creating the Child thread
Child thread starts
Threads verwalten
Die Thread-Klasse bietet verschiedene Methoden zum Verwalten von Threads.
Das folgende Beispiel zeigt die Verwendung von sleep() Methode, um einen Thread für einen bestimmten Zeitraum anzuhalten.
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
// the thread is paused for 5000 milliseconds
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:
In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes
Threads zerstören
Das Abort() Methode wird zum Zerstören von Threads verwendet.
Die Laufzeit bricht den Thread ab, indem sie a auslöst ThreadAbortException. Diese Ausnahme kann nicht abgefangen werden. Das Steuerelement wird gegebenenfalls an den finally- Block gesendet .
Das folgende Programm veranschaulicht dies -
using System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
try {
Console.WriteLine("Child thread starts");
// do some work, like counting to 10
for (int counter = 0; counter <= 10; counter++) {
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
} catch (ThreadAbortException e) {
Console.WriteLine("Thread Abort Exception");
} finally {
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
//stop the main thread for some time
Thread.Sleep(2000);
//now abort the child
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
Wenn der obige Code kompiliert und ausgeführt wird, ergibt sich das folgende Ergebnis:
In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception