English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# Multithreading

Thread definiert als der Ausführungspfad eines Programms. Jeder Thread definiert einen einzigartigen Kontrollfluss. Wenn Ihre Anwendung komplexe und zeitaufwendige Operationen umfasst, ist es oft nützlich, verschiedene Ausführungswege für Threads zu setzen, wobei jeder Thread spezifische Aufgaben ausführt.

Ein Thread istLeichtgewichtige ProzesseEin häufiges Beispiel für die Verwendung von Threads ist die Implementierung von Parallelprogramming in modernen Betriebssystemen. Die Verwendung von Threads spart CPU-Zyklen und verbessert gleichzeitig die Effizienz der Anwendung.

Bisher haben wir geschriebene Programm ist ein einzelner Thread als Beispiel für den Prozess der Anwendung der Single-Thread-Runtime. Aber so kann die Anwendung gleichzeitig nur eine Aufgabe ausführen. Um mehrere Aufgaben gleichzeitig auszuführen, kann es in kleinere Threads unterteilt werden.

Lebenszyklus der Thread

Lebenszyklus der Thread beginnt, wenn das Objekt der Klasse System.Threading.Thread erstellt wird, und endet, wenn der Thread beendet oder die Ausführung abgeschlossen wird.

Nachstehend sind verschiedene Zustände im Lebenszyklus der Thread aufgeführt:

  • Nicht gestarteter Zustand: Zustand, wenn die Thread-Instanz erstellt wurde, aber die Start-Methode noch nicht aufgerufen wurde.

  • Bereit-Zustand: Zustand, wenn der Thread bereit ist, ausgeführt zu werden und auf CPU-Zyklen wartet.

  • Nicht ausführbarer Zustand: In den folgenden Fällen ist der Thread nicht ausführbar:

    • hat Sleep-Methode aufgerufen

    • hat Wait-Methode aufgerufen

    • durch I/O-Operation blockiert

  • Todeszustand: Zustand, wenn der Thread die Ausführung abgeschlossen hat oder abgebrochen wurde.

Mainthread

In C#,System.Threading.Thread Die Klasse wird zur Thread-Arbeit verwendet. Sie ermöglicht das Erstellen und den Zugriff auf eine einzelne Thread in einer multithreaded Anwendung. Der erste Thread, der im Prozess ausgeführt wird, wird alsMainthread.

Wenn ein C#-Programm ausgeführt wird, wird der Hauptthread automatisch erstellt. Verwenden Sie Thread Durch die Thread-Klasse können Sie auf den von der Klasse erstellten Thread zugreifen. Wenn der Hauptthread ein Kindthread aufruft, können Sie dies tun CurrentThread Eigenschaftszugriff auf Thread.

Das folgende Programm zeigt die Ausführung des MainThreads an:

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 er das folgende Ergebnis:

This is MainThread

Häufig verwendete Eigenschaften und Methoden der Thread-Klasse

Die folgende Tabelle zeigt Thread Einige der häufig verwendeten Methoden einer Klasse Eigenschaft:

EigenschaftBeschreibung
CurrentContextErmitteln Sie den aktuellen Kontext, in dem die Thread ausgeführt wird.
CurrentCultureErmitteln oder stellen Sie die aktuelle Regionaleinstellung der Thread ein.
CurrentPrincipalErmitteln oder stellen Sie den aktuellen Verantwortlichen der Thread ein (für rollenbasierte Sicherheit).
CurrentThreadErhalten Sie den aktuellen laufenden Thread.
CurrentUICultureErmitteln oder stellen Sie die aktuelle Regionaleinstellung des Ressourcenmanagers ein, um regionalspezifische Ressourcen beim Laufzeit finden zu können.
ExecutionContextErhalten Sie ein ExecutionContext-Objekt, das Informationen über verschiedene Kontexte der aktuellen Thread enthält.
IsAliveErhalte einen Wert, der den Ausführungsstatus des aktuellen Threads anzeigt.
IsBackgroundErhalte oder setze einen Wert, der anzeigt, ob ein Thread ein Hintergrundthread ist.
IsThreadPoolThreadErhalte einen Wert, der anzeigt, ob der Thread einem verwalteten Threadpool angehört.
ManagedThreadIdErhalte die eindeutige Identifikationsnummer der aktuellen verwalteten Thread.
NameErhalte oder setze den Namen des Threads.
PriorityErhalte oder setze einen Wert, der die Schedulingspriorität des Threads anzeigt.
ThreadStateErhalte einen Wert, der den Zustand der aktuellen Thread enthält.

Die folgende Tabelle zeigt Thread Einige der häufig verwendeten Methoden einer Klasse Methode:

NummerMethodennamen & Beschreibung
1public void Abort()
Führe ThreadAbortException auf dem Thread aus, der diesen Methodenaufruf macht, um den Prozess der Beendigung dieses Threads zu beginnen. Der Aufruf dieser Methode führt in der Regel zum Beenden des Threads.
2public static LocalDataStoreSlot AllocateDataSlot()
分配所有线程上的未命名数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
3public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
分配所有线程上的已命名数据槽。为了获得更好的性能,请改用以 ThreadStaticAttribute 属性标记的字段。
4public static void BeginCriticalRegion()
Benachrichtige den Host, dass er in einen Codebereich eintreten wird, in dem der Einfluss eines Threadabbruchs oder einer nicht behandelten Ausnahme möglicherweise andere Aufgaben im Anwendungsbereich gefährden könnte.
5public static void BeginThreadAffinity()
Benachrichtige den Host, dass der Code, der auf der Identität des aktuellen physikalischen Betriebssystemthreads basiert, ausgeführt werden soll.
6public static void EndCriticalRegion()
Benachrichtige den Host, dass er in einen Codebereich eintreten wird, in dem ein Thread abgebrochen wird oder eine nicht behandelte Ausnahme nur die aktuelle Aufgabe beeinflusst.
7public static void EndThreadAffinity()
Benachrichtige den Host, dass der Code, der auf der Identität des aktuellen physikalischen Betriebssystemthreads basiert, ausgeführt wurde.
8public static void FreeNamedDataSlot(string name)
Entfernen Sie die Verknüpfung zwischen Namen und Slot für alle Threads im Prozess. Um eine bessere Leistung zu erzielen, verwenden Sie Felder, die mit der ThreadStaticAttribute markiert sind.
9public static Object GetData( LocalDataStoreSlot slot )
Beschaffen Sie im aktuellen Domain des aktuellen Threads den Wert aus dem angegebenen Slot. Um eine bessere Leistung zu erzielen, verwenden Sie Felder, die mit der ThreadStaticAttribute markiert sind.
10public static AppDomain GetDomain()
Geben Sie die aktuelle Domain zurück, in der der aktuelle Thread läuft.
11public static AppDomain GetDomainID()
Geben Sie ein einzigartiges Anwendungsdomain-Identifikationszeichen zurück.
12public static LocalDataStoreSlot GetNamedDataSlot( string name )
Finden Sie den benannten Daten-Slot. Um eine bessere Leistung zu erzielen, verwenden Sie Felder, die mit der ThreadStaticAttribute markiert sind.
13public void Interrupt()
Unterbrechen Sie den Thread im WaitSleepJoin-Threadstatus.
14public void Join()
Blockieren Sie den Aufrufthread, bis ein Thread beendet wird, während der Standard- COM- und SendMessage-Nachrichtenpumpenverarbeitung fortgesetzt wird. Dieses Verfahren hat verschiedene Overloads.
15public static void MemoryBarrier()
Synchronisieren Sie den Zugriff auf den Speicher wie folgt: Während der Verarbeitung von COM und SendMessage-Nachrichten durch den Prozessor des aktuellen Threads dürfen keine Speicherzugriffe vor einem MemoryBarrier-Aufruf ausgeführt werden, die nach einem MemoryBarrier-Aufruf ausgeführt werden.
16public static void ResetAbort()
Abbrechen Sie den Abort, der für den aktuellen Thread angefordert wurde.
17public static void SetData( LocalDataStoreSlot slot, Object data )
Setzen Sie Daten in der aktuellen Domain dieses Threads in einem bestimmten Slot. Um eine bessere Leistung zu erzielen, verwenden Sie Felder, die mit der ThreadStaticAttribute markiert sind.
18public void Start()
Starten Sie einen Thread.
19public static void Sleep( int millisecondsTimeout )
Pausiert den Thread für eine Weile.}
20public static void SpinWait( int iterations )
Verursacht, dass der Thread die vom Parameter iterations definierte Zeit wartet.
21public 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 )

Lesen des Feldwerts. Unabhängig von der Anzahl der Prozessoren oder dem Status des Prozessor-Caches wird der neueste Wert, der von jedem Prozessor des Computers geschrieben wird, gelesen. Dieses Verfahren hat verschiedene Überladungen. Hier werden einige gezeigt.
22public 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 )

Einen Wert sofort in das Feld schreiben, um sicherzustellen, dass dieser Wert für alle Prozessoren im Computer sichtbar ist. Dieses Verfahren hat verschiedene Überladungen. Hier werden einige gezeigt.
23public static bool Yield()
Verursacht, dass ein anderer Thread, der bereit ist, auf dem aktuellen Prozessor ausgeführt zu werden, aufgerufen wird. Der Betriebssystem wählt den auszuführenden Thread aus.

Erstellung eines Threads

Ein Thread wird durch Erweiterung der Thread-Klasse erstellt. Die erweiterte Thread-Klasse ruft Start() Methoden, um die Ausführung eines Unterthreads zu starten.

Das folgende Programm demonstriert dieses 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 er das folgende Ergebnis:

In Main: Erstellen des Child-threads
Child-thread beginnt

Thread-Verwaltung

Die Thread-Klasse bietet verschiedene Methoden zur Verwaltung von Threads.

Der folgende Beispiel zeigt sleep() Verwendung des Methoden, um einen Thread für eine bestimmte Zeit anzuhalten.

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Child thread starts");
            // Thread-Pause 5000 Millisekunden
            int sleepfor = 5000; 
            Console.WriteLine("Kindes-Prozess angehalten für {0} Sekunden", 
                              sleepfor / 1000);
            Thread.Sleep(sleepfor);
            Console.WriteLine("Kindes-Prozess wird fortgesetzt");
        }
        
        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 er das folgende Ergebnis:

In Main: Erstellen des Child-threads
Child-thread beginnt
Child Thread hat für 5 seconds
Der Unterthread setzt fort

Zerstört den Thread

Abort() Methoden verwendet werden, um Threads zu zerstören.

durch Auswerfen threadabortexception Ein Thread wird während der Laufzeit abgebrochen. Dieser Ausnahme kann nicht erkannt werden, wenn finally Block, der Kontrollfluss wird dorthin gesendet finally Block.

Das zeigt der folgende Programmcode:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {
                Console.WriteLine("Child thread starts");
                // Zählt bis 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("Konnte die Thread-Exception nicht fangen");
            }
        }
        
        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();
            // Hält den Hauptthread für eine Weile an
            Thread.Sleep(2000);
            // Jetzt wird der Unterthread beendet
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

Wenn der obige Code kompiliert und ausgeführt wird, ergibt er das folgende Ergebnis:

In Main: Erstellen des Child-threads
Child-thread beginnt
0
1
2
In Main: Aborting des Child-threads
Thread-Abort-Exception
Konnte die Thread-Exception nicht fangen