Die Anleitung zu C# Multithreading Programmierung

1- The concept of multithreading

Multi Thread ist ein wichtiger Begriff in der Programmiersprache und so ist die C#. Das ist die Weise der Erstellung der parallelen Thread. Sehen Sie bitte ein folgendes Beispiel um mehr zu verstehen:
HelloThread.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class HelloThread
    {
        public static void Main(string[] args)
        {
             
            Console.WriteLine("Create new Thread...\n");          

            // Creates a child thread, which runs in parallel with the main thread.
            Thread newThread = new Thread(WriteB);

            Console.WriteLine("Start newThread...\n");

            // Start the thread
            newThread.Start();

            Console.WriteLine("Call Write('-') in main Thread...\n");

            // In the main thread print out character '-'
            for (int i = 0; i < 50; i++)
            {
                Console.Write('-');

                // Sleep 70 millisenconds
                Thread.Sleep(70);
            }


            Console.WriteLine("Main Thread finished!\n");
            Console.Read();
        }



        public static void WriteB()
        {
            // Print out the 'B' 100 times.
            for (int i = 0; i < 100; i++)
            {
                Console.Write('B');

                // Sleep 100 millisenconds
                Thread.Sleep(100);
            }
                
        }
    }

   
}
Und dann starten Sie die Klasse
Das Arbeitsprinzip des Thread wird im folgenden Beispiel erläutert:

2- Pass parameters to Thread

Im obenen Part haben Sie mit dem Beispiel über HelloThread kennengelernt. Sie erstellten ein Objekt, das eine static Methode einpackt um diese Methode gleichzeitig mit dem Vater Thread durchzuführen
Die static Methode kann einen Parameter zur Übertragung in dem Constructor der Klasse Thread werden wenn die Methode keinen Parameter oder einen einzigen Parameter Objekt ha t.
// A static method, have no parameters
public static void LetGo()
{
     // Do something here
}

// A static method has a unique parameter, and the type is object.
public static void GetGo(object value)
{
      // Làm gì đó ở đây.
}
Im nächsten Beispiel erstelle ich ein Thread, der eine static Methode mit einen Parameter (Objekt typ) einpackt. Ich laufe das Thread und übertrage die Wert für den Parameter .
MyWork.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class MyWork
    {

        public static void DoWork(object ch)
        {
            for (int i = 0; i < 100; i++)
            {
                // Write to console
                Console.Write(ch);

                // Sleep 50 milliseconds
                Thread.Sleep(50);
            }
        }



    }
}
ThreadParamDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadParamDemo
    {

        public static void Main(string[] args)
        {

            Console.WriteLine("Create new thread.. \n");

            // Create a Thread object to wrap around the static method MyWork.DoWork
            Thread workThread = new Thread(MyWork.DoWork);

            Console.WriteLine("Start workThread...\n");

            // Run workThread,
            // and pass parameter to MyWork.DoWork.
            workThread.Start("*");


            for (int i = 0; i < 20; i++)
            {
                Console.Write(".");

                // Sleep 30 milliseconds.
                Thread.Sleep(30);
            }

            Console.WriteLine("MainThread ends");
            Console.Read();
        }
    }

}
Die Klasse  ThreadParamDemo:starten

3- Thread uses non-static method

Sie können auch einen Thread durch die Benutzung der normalen Methoden. Sehen Sie das Beispiel:
Worker.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class Worker
    {
        private string name;
        private int loop;

        public Worker(string name, int loop)
        {
            this.name = name;
            this.loop = loop;
        }

        public void DoWork(object value)
        {
            for (int i = 0; i < loop; i++)
            {
                Console.WriteLine(name + " working " + value);
                Thread.Sleep(50);
            }
             
        }

    }

}
WorkerTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class WorkerTest
    {

        public static void Main(string[] args)
        {
            Worker w1 = new Worker("Tran",10);

            // Create a Thread object.
            Thread workerThread1 = new Thread(w1.DoWork);

            // Pass parameter to DoWork method.
            workerThread1.Start("A");


            Worker w2 = new Worker("Marry",15);

            // Create a Thread object.
            Thread workerThread2 = new Thread(w2.DoWork);

            // Pass parameter to DoWork method.
            workerThread2.Start("B");
          
            Console.Read();
        }
    }

}
Das Beispiel durchführen:

4- ThreadStart Delegate

ThreadStart ist eine Beauftragungsklasse (Delegate), sie wird durch die Einpackung einer Methode erstellt. Und sie wird wie ein Parameter zur Erstellung eines Objekt Thread übertragen
Um einen Thread im  .Net < 2.0 zu starten, sollen Sie ein  ThreadStart erstellen. Das ist eine delegate.

Ab der Version 2.0 von  .NET Framework ist es nicht notwendig, ein ThreadStart klar zu erstellen. Sie brauchen nur den Namen der Methode im Constructor des Thread bestimmen
Programmer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class Programmer
    {
        private string name;
        public Programmer(string name)  
        {
            this.name= name;
        }

        // This is none static method, no parameters.
        public void DoCode()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(name + " codding ... ");
                Thread.Sleep(50);
            }
                
        }
    }

}
ThreadStartDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;


namespace MultithreadingTutorial
{
    class ThreadStartDemo
    {


        public static void Main(string[] args)
        {
            // Create a ThreadStart object that wrap a static method.
            // (It can only wrap method have no parameters)
            // (ThreadStart is a delegate).      
            ThreadStart threadStart1 = new ThreadStart(DoWork);

            // Create a thread wrap threadStart1.
            Thread workThread = new Thread(threadStart1);

            // Start thread
            workThread.Start();

            // Create Programmer object.
            Programmer tran = new Programmer("Tran");

            // You can also create ThreadStart objects that wrap a non-static method.
            // (It can only wrap method have no parameters)
            ThreadStart threadStart2 = new ThreadStart(tran.DoCode);

            // Create a Thread wrap threadStart2.
            Thread progThread = new Thread(threadStart2);

            progThread.Start();

            Console.WriteLine("Main thread ends");
            Console.Read();
        }


        public static void DoWork()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.Write("*");
                Thread.Sleep(100);
            }                
        }
    }

}
Das Beispeil durchführen:

5- Thread with anonymous code

Im den obengenannten Part haben Sie die Thread durch die Benutzung einer bestimmten Methode erstellt. Sie können einen Thread erstellen um irgendeine Code zu implementieren.
// Use delegate() to create anonymous method.
delegate()
{
     // Do something here.
}
Example:
ThreadUsingSnippetCode.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadUsingSnippetCode
    {

        public static void Main(string[] args)
        {

            Console.WriteLine("Create thread 1");

            // Creates a thread to execute a snippet code.
            Thread newThread1 = new Thread(
                delegate()
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("Code in delegate() " + i);
                        Thread.Sleep(50);
                    }

                }
            );

            Console.WriteLine("Start newThread1");

            // Start thread.
            newThread1.Start();

            Console.WriteLine("Create thread 2");

            // Creates a thread to execute a snippet code.
            Thread newThread2 = new Thread(
                delegate(object value)
                {
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine("Code in delegate(object) " + i + " - " + value);
                        Thread.Sleep(100);
                    }

                }
            );

            Console.WriteLine("Start newThread2");

            // Start thread 2.
            // Pass parameter to delegate().
            newThread2.Start("!!!");


            Console.WriteLine("Main thread ends");
            Console.Read();

        }
    }

}
Running the example:

6- Name the thread

In der Programmierung des MultiThread können Sie automatisch den Name für den Thread stellen. Es ist wirklich nützlich beim Debugging. Damit können wir kennen, die Code wird in welchem Thread implementiert.

In einem Thread können Sie Thread.CurrentThread.Name aufrufen um den Name des implementierenden Thread zu haben
Sehen Sie das Beispiel
NamingThreadDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class NamingThreadDemo
    {

        public static void Main(string[] args)
        {
            // Set name to current thread
            // (Main thread)
            Thread.CurrentThread.Name = "Main";

            Console.WriteLine("Code of "+ Thread.CurrentThread.Name);

            Console.WriteLine("Create new thread");

            // Create a thread
            Thread letgoThread = new Thread(LetGo);

            // Set name to thread    
            letgoThread.Name = "Let's Go";

            letgoThread.Start();

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Code of " + Thread.CurrentThread.Name);
                Thread.Sleep(30);
            }

            Console.Read();
        }


        public static void LetGo()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Code of " + Thread.CurrentThread.Name);
                Thread.Sleep(50);
            }
        }
    }

}
Running the example:

7- Priority between threads

Im C# gibt es 5 Prioritätlevel eines Thread. Sie werden in enum ThreadPriority.definiert
** ThreadPriority enum **
enum ThreadPriority {
    Lowest,
    BelowNormal,
    Normal,
    AboveNormal,
    Highest
}
Normalerweise ist es Ihnen beim der highspeed Computer schwierig, den Unterschied zwischen der hochprioritäten Thread und der wenigprioritäten Thread zu sehen wenn die Thread wenige Arbeit machen.

Das folgende BEispiel hat 2 Thread. Jeder Thread drückt 100K Textzeile aus. (Eine genug große Menge zeigt den Unterschied).
ThreadPriorityDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadPriorityDemo
    {
        private static DateTime endsDateTime1;
        private static DateTime endsDateTime2;


        public static void Main(string[] args)
        {
            endsDateTime1 = DateTime.Now;
            endsDateTime2 = DateTime.Now;

            Thread thread1 = new Thread(Hello1);

            // Set highest priority for thread1
            thread1.Priority = ThreadPriority.Highest;

            Thread thread2 = new Thread(Hello2);

            // Set the lowest priority for thread2.
            thread2.Priority = ThreadPriority.Lowest;


            thread2.Start(); thread1.Start();

            Console.Read();
        }


        public static void Hello1()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("Hello from thread 1: "+ i);
            }
            // The time of thread1 ends.     
            endsDateTime1 = DateTime.Now;

            PrintInterval();
        }

        public static void Hello2()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("Hello from thread 2: "+ i);
            }
            // The time of thread2 ends.
            endsDateTime2 = DateTime.Now;

            PrintInterval();
        }

        private static void PrintInterval()
        {
            // Interval (Milliseconds)
            TimeSpan interval = endsDateTime2 - endsDateTime1;

 
            Console.WriteLine("Thread2 - Thread1 = " + interval.TotalMilliseconds + " milliseconds");
        }
    }

}
Running the example:

8- Using Join()

Thread.Join() ist eine Methode zu informieren, dass wart auf die Erledigung eines Thread und dann der VaterThread weiter läuft.
ThreadJoinDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;


namespace MultithreadingTutorial
{
    class ThreadJoinDemo
    {

        public static void Main(string[] args)
        {
            Console.WriteLine("Create new thread");

            Thread letgoThread = new Thread(LetGo);
            
            // Start Thread.       
            letgoThread.Start();

            // Tell to the parent thread (here is main thread)
            // wait for the letgoThread to finish, then continue running.
            letgoThread.Join();
            
            // This statement must wait for letgoThread to end, then continue running
            Console.WriteLine("Main thread ends");
            Console.Read();
        }


        public static void LetGo()
        {
            for (int i = 0; i < 15; i++)
            {
                Console.WriteLine("Let's Go " + i);
            }
        }
    }

}
Running the example:

9- Using Yield()

Theoretisch bedeutet  "Yield" Übergabe, Verlassung, Kapitulation. Ein Thread Yield sagt dem Betriebssystem, dass er lasst die anderen Thread in seiner Postion liegen. Das zeigt, dass er ist nicht etwas wichtig. Beachten Sie, dass er ist nur eine Vorschlage, obwohl er ist nicht sicher, auf alles zu wirken
Deshalb wird die Methode  Yield() benutzt wenn er ist nicht beschäftig, er muss etwas nicht wichtig machen so er schlägt vor, dass das Betriebssystem vorläufig die Priorität für anderen Thread gibt.
Das folgende Beispiel, Es gibt 2 Thread, jeder Thread drückt 100K Textzeile ( genug groß sein, den Unterschied zu zeigen). Ein Thread ist höchstpriorität und ein kleinstpriorität. Wir messen die Zeit zum Stoppen des 2 Thread.
ThreadYieldDemo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MultithreadingTutorial
{
    class ThreadYieldDemo
    {

        private static DateTime importantEndTime;
        private static DateTime unImportantEndTime;

        public static void Main(string[] args)
        {
            importantEndTime = DateTime.Now;
            unImportantEndTime = DateTime.Now;

            Console.WriteLine("Create thread 1");

            Thread importantThread = new Thread(ImportantWork);
            // Set the highest priority for this thread.
            importantThread.Priority = ThreadPriority.Highest;

            Console.WriteLine("Create thread 2");

            Thread unImportantThread = new Thread(UnImportantWork);
            // Set the lowest priority for this thread.
            unImportantThread.Priority = ThreadPriority.Lowest;

            // Start threads.
            unImportantThread.Start();
            importantThread.Start();
           

            Console.Read();

        }

        // A important job.
        public static void ImportantWork()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("\n Important work " + i);

                // Notifying the operating system,
                // this thread gives priority to other threads.
                Thread.Yield();
            }
            // The end time of this thread.
            importantEndTime = DateTime.Now;
            PrintTime();
        }

        public static void UnImportantWork()
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine("\n  -- UnImportant work " + i);
            }
            // The end time of this thread.      
            unImportantEndTime = DateTime.Now;
            PrintTime();
        }

        private static void PrintTime()
        {
            // Interval (Milliseconds)
            TimeSpan interval = unImportantEndTime - importantEndTime;
      
            Console.WriteLine("UnImportant Thread - Important Thread = " + interval.TotalMilliseconds +" milliseconds");
        }
         
    }

}
Starten Sie die oben Klasse ohne  Thread.Yield():
Starten Sie die oben Klasse falls der höherpriorität Thread ununterbrochen auf  Thread.Yield() aufruft um anzufordern, dass das System vorläufig die Priorität für die anderen Thread gibt.

10- TODO