|
2 | 2 |
|
3 | 3 | author: Sebastian Zug, Galina Rudolf & André Dietrich |
4 | 4 | email: sebastian.zug@informatik.tu-freiberg.de |
5 | | -version: 1.0.7 |
| 5 | +version: 1.0.8 |
6 | 6 | language: de |
7 | 7 | narrator: Deutsch Female |
8 | 8 | comment: Multithreading Konzepte, Thread-Modell und Interaktion, Implementierung in C#, Datenaustausch, Locking, Thread-Pool |
@@ -784,40 +784,103 @@ wird durch die Nutzung von ThreadPools beschränkt, da diese als wiederverwendba |
784 | 784 |
|
785 | 785 | Die `System.Threading.ThreadPool`-Klasse stellt einer Anwendung einen Pool von "Arbeitsthreads" bereit, die vom System verwaltet werden und Ihnen die Möglichkeit bieten, sich mehr auf Anwendungsaufgaben als auf die Threadverwaltung zu konzentrieren. |
786 | 786 |
|
| 787 | + |
| 788 | + {{0-1}} |
| 789 | +******************************************************************** |
| 790 | + |
787 | 791 | ```csharp ThreadPool |
788 | 792 | using System; |
789 | 793 | using System.Threading; |
790 | 794 |
|
791 | | -class Program { |
792 | | - // This thread procedure performs the task. |
793 | | - static void Operate(object stateInfo) |
794 | | - { |
795 | | - Console.WriteLine("Hello from the thread pool."); |
796 | | - } |
| 795 | +class Program |
| 796 | +{ |
| 797 | + static void Main(string[] args) |
| 798 | + { |
| 799 | + // ThreadPool konfigurieren |
| 800 | + ThreadPool.SetMinThreads(4, 4); // Warum geben wir hier mehrere Parameter an? |
| 801 | + ThreadPool.SetMaxThreads(8, 8); |
797 | 802 |
|
798 | | - public static void Main(string[] args){ |
799 | | - ThreadPool.QueueUserWorkItem(Operate); |
800 | | - //Fügt der Warteschlange eine auszuführende Methode hinzu. |
801 | | - //Die Methode wird ausgeführt, wenn ein Thread des Threadpools verfügbar wird |
802 | | - |
803 | | - Console.WriteLine("Main thread does some work, then sleeps."); |
804 | | - Thread.Sleep(1000); |
805 | | - Console.WriteLine("Main thread exits."); |
806 | | - } |
| 803 | + Console.WriteLine("Starte mehrere Aufgaben im ThreadPool..."); |
| 804 | + |
| 805 | + // Kommentar 2: |
| 806 | + int taskCount = 5; |
| 807 | + CountdownEvent countdown = new CountdownEvent(taskCount); |
| 808 | + |
| 809 | + for (int i = 0; i < taskCount; i++) |
| 810 | + { |
| 811 | + // Kommentar 1: |
| 812 | + // Schleifenvariable in lokale Variable kopieren sonst "Gefangene Schleifenvariable" (Closure) |
| 813 | + int taskNum = i; |
| 814 | + |
| 815 | + // Lambda-Ausdruck |
| 816 | + ThreadPool.QueueUserWorkItem(state => |
| 817 | + { |
| 818 | + Console.WriteLine($"[Task {taskNum}] gestartet auf Thread {Thread.CurrentThread.ManagedThreadId}"); |
| 819 | + ThreadPool.GetAvailableThreads(out int worker, out int iocp); |
| 820 | + Console.WriteLine($"Noch frei: {worker} WorkerThreads, {iocp} IOCP-Threads"); |
| 821 | + |
| 822 | + // Simulierte Arbeit |
| 823 | + Thread.Sleep(500); |
| 824 | + |
| 825 | + Console.WriteLine($"[Task {taskNum}] beendet"); |
| 826 | + countdown.Signal(); |
| 827 | + }); |
| 828 | + } |
| 829 | + |
| 830 | + // Zeige verfügbare Threads im Pool |
| 831 | + ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads); |
| 832 | + Console.WriteLine($"Verfügbare WorkerThreads: {workerThreads}"); |
| 833 | + Console.WriteLine($"Verfügbare CompletionPortThreads: {completionPortThreads}"); |
| 834 | + |
| 835 | + // Warten, bis Threads ihre Arbeit tun können |
| 836 | + Console.WriteLine("Main-Thread wartet auf Aufgaben..."); |
| 837 | + Thread.Sleep(2000); // grobes Warten – kein sauberes Synchronisieren !!! |
| 838 | + //countdown.Wait(); // wartet, bis alle Tasks fertig |
| 839 | + Console.WriteLine("Main-Thread beendet sich."); |
| 840 | + } |
807 | 841 | } |
808 | 842 | ``` |
809 | 843 | @LIA.eval(`["main.cs"]`, `mcs main.cs`, `mono main.exe`) |
810 | 844 |
|
| 845 | +******************************************************************** |
| 846 | + |
| 847 | + {{1-2}} |
| 848 | +******************************************************************** |
| 849 | + |
811 | 850 | Das klingt sehr praktisch, was aber sind die Einschränkungen? |
812 | 851 |
|
813 | 852 | + Für die Threads können keine Namen vergeben werden, damit wird das Debugging ggf. schwieriger. |
814 | 853 | + Pooled Threads sind immer Background-Threads |
815 | 854 | + Sie können keine individuellen Prioritäten festlegen. |
816 | 855 | + Blockierte Threads im Pool senken die entsprechende Performance des Pools |
817 | 856 |
|
| 857 | + |
| 858 | +******************************************************************** |
| 859 | + |
| 860 | + {{2-3}} |
| 861 | +******************************************************************** |
| 862 | + |
| 863 | +> Wie weit kann ich mit Blick auf die Reihung eingreifen? |
| 864 | +
|
| 865 | +Noch mal zur Abgrenzung ... |
| 866 | + |
| 867 | +```csharp StartProcess.cs |
| 868 | +using System; |
| 869 | +using System.Diagnostics; |
| 870 | + |
| 871 | +class Program { |
| 872 | + static void Main() { |
| 873 | + Process.Start("notepad.exe"); // Öffnet den Windows-Editor |
| 874 | + } |
| 875 | +} |
| 876 | +``` |
| 877 | + |
| 878 | +... und was bedeutet das? |
| 879 | + |
818 | 880 | | Ebene | Wer steuert? | Beschreibung | |
819 | 881 | | ------------- | -------------------- | ------------------------------------------------------------------------------- | |
820 | 882 | | Prozess | Betriebssystem | CLR läuft in einem OS-Prozess | |
821 | 883 | | Native Thread | Betriebssystem | `Thread`-Objekte in C# sind OS-Threads | |
822 | 884 | | ThreadPool | CLR + Betriebssystem | CLR entscheidet über Ausführung im Pool; OS entscheidet über Hardware-Zuteilung | |
823 | 885 |
|
| 886 | +******************************************************************** |
0 commit comments