SO WIRD'S GEMACHT: Synchronisieren des Zugriffs auf eine freigegebene Ressource in einer Multithreading-Umgebung mit Visual C# .NET

SPRACHE AUSWÄHLEN SPRACHE AUSWÄHLEN
Artikel-ID: 816161 - Produkte anzeigen, auf die sich dieser Artikel bezieht
Dieser Artikel ist eine Übersetzung des folgenden englischsprachigen Artikels der Microsoft Knowledge Base:
816161 HOW TO: Synchronize Access to a Shared Resource in a Multithreading Environment by Using Visual C# .NET
Bitte beachten Sie: Bei diesem Artikel handelt es sich um eine Übersetzung aus dem Englischen. Es ist möglich, dass nachträgliche Änderungen bzw. Ergänzungen im englischen Originalartikel in dieser Übersetzung nicht berücksichtigt sind. Die in diesem Artikel enthaltenen Informationen basieren auf der/den englischsprachigen Produktversion(en). Die Richtigkeit dieser Informationen in Zusammenhang mit anderssprachigen Produktversionen wurde im Rahmen dieser Übersetzung nicht getestet. Microsoft stellt diese Informationen ohne Gewähr für Richtigkeit bzw. Funktionalität zur Verfügung und übernimmt auch keine Gewährleistung bezüglich der Vollständigkeit oder Richtigkeit der Übersetzung.
Alles erweitern | Alles schließen

Auf dieser Seite

Zusammenfassung

Mit Multithreading können Sie in Visual C# .NET-Anwendungen mehrere Aufgaben gleichzeitig ausführen. Beim Multithreading werden verschiedene Threads gestartet, um verschiedene Aufgaben zur selben Zeit auszuführen. Darüber hinaus erhöht Multithreading die Leistung und Reaktionsbereitschaft Ihrer Anwendungen.

Da mehrere Threads gleichzeitig auf eine Ressource zugreifen können, kann es sinnvoll sein, einzelne Threads mit anderen Teilen Ihres Programms zu synchronisieren. Dieser Artikel beschreibt einige häufige Szenarien bei der Multithreading-Programmierung und erläutert, wie Sie den Zugriff auf eine freigegebene Ressource zwischen mehreren Threads synchronisieren.

Schützen Ihrer globalen Daten in Modulen in einer Multithreading-Umgebung

Die öffentlichen Felder in Methoden sind für alle Threads in Ihrer Anwendung zugänglich. Den Zugriff auf die öffentlichen Felder können Sie über Eigenschaft anstatt Feld synchronisieren und ein ReaderWriterLock-Objekt verwenden, um den Zugriff zu steuern. Gehen Sie hierzu folgendermaßen vor:
  1. Starten Sie Visual Studio .NET.
  2. Zeigen Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt.
  3. Unter Projekttypen klicken Sie auf Visual C#-Projekte. Wählen Sie dann unter Vorlagen die Option Konsolenanwendung.
  4. Im Textfeld Name geben Sie MultiThreadApplication ein. Klicken Sie anschließend auf OK.
  5. Ersetzen Sie den Code in "Class1.cs" durch folgenden Code:
    using System;
    using System.Threading;
    
    namespace MultiThreadApplication
    {
    	class Class1
    	{
    		private ReaderWriterLock rwl = new ReaderWriterLock();
    		private long myNumber;
    		public long Number   // the Number property
    		{
    			get
    			{
    				//Acquire a read lock on the resource.
    				rwl.AcquireReaderLock(Timeout.Infinite);                
    				try
    				{
    					Console.WriteLine("Thread:{0} starts getting the Number", Thread.CurrentThread.GetHashCode());
    					Thread.Sleep(50);
    					Console.WriteLine("Thread:{0} got the Number", Thread.CurrentThread.GetHashCode());
    
    				}
    				finally
    				{
    					//Release the lock.
    					rwl.ReleaseReaderLock();
    				}
    				return myNumber;
    			}
    			set
    			{
    				//Acquire a write lock on the resource.
    				rwl.AcquireWriterLock(Timeout.Infinite);
    				try
    				{
    					Console.WriteLine("Thread: {0} start writing the Number", Thread.CurrentThread.GetHashCode());
    					Thread.Sleep(50);
    					myNumber = value;
    					Console.WriteLine("Thread: {0} written the Number", Thread.CurrentThread.GetHashCode());
    				}
    				finally
    				{
    					//Release the lock.
    					rwl.ReleaseWriterLock();
    				}
    			}
    		}
    				[STAThread]
    		static void Main(string[] args)
    		{
    			Thread []threadArray = new Thread[20]; 
    			int threadNum;
    
    
    			Class1 Myclass = new Class1();
    			ThreadStart myThreadStart = new ThreadStart(Myclass.AccessGlobalResource);
    
    			//Create 20 threads.
    			for( threadNum = 0; threadNum < 20; threadNum++)
    			{
    				threadArray[threadNum] = new Thread(myThreadStart);
    			}
    
    			//Start the threads.
    			for( threadNum = 0; threadNum < 20; threadNum++)
    			{   
    				threadArray[threadNum].Start();
    			}
    
    			//Wait until all the thread spawn out finish.
    			for( threadNum = 0; threadNum < 20; threadNum++)
    				threadArray[threadNum].Join();
    
    			Console.WriteLine("All operations have completed. Press enter to exit");
    			Console.ReadLine();
    		}
    
    		public void AccessGlobalResource()
    		{
    			Random rnd = new Random();
    			long theNumber;
    						if (rnd.Next() % 2 != 0)
    				theNumber = Number;
    			else
    			{
    				theNumber = rnd.Next();
    				Number = theNumber;
    			}
    
    		}
    	}
    }
    
  6. Erstellen Sie das Projekt und führen Sie die Anwendung aus.

Klassen threadsicher machen

Mehrere Threads versuchen eventuell gleichzeitig, auf ein Objekt zuzugreifen. Wenn das eintritt, können manche Threads einen ungültigen Status erhalten, wenn ein anderer Thread die Ressource zum selben Zeitpunkt ändert. Wenn ein Thread z.B. das Feld des Objekts liest, während ein anderer Thread das Feld gerade ändert, kann der erste Thread einen ungültigen Feldstatus erhalten. Diese Situation bezeichnet man als Race-Bedingung.

Sie können kritische Abschnitte Ihres Codes mit Sperren vor Race-Bedingungen schützen, um diese Situation zu vermeiden. Eine Sperre, dargestellt durch die Anweisung mit dem Visual C#-Schlüsselwort "lock", ermöglicht es einem einzelnen Thread, exklusive Ausführungsrechte für ein Objekt zu erhalten. Das folgende Beispiel veranschaulicht solche Sperren:
  1. Öffnen Sie Visual Studio .NET.
  2. Zeigen Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt.
  3. Unter Projekttypen klicken Sie auf Visual C#-Projekte. Wählen Sie dann unter Vorlagen die Option Konsolenanwendung.
  4. Im Textfeld Name geben Sie MultiThreadLockApplication ein. Klicken Sie anschließend auf OK.
  5. Ersetzen Sie den Code in "Class1.cs" durch folgenden Code:
    using System;
    using System.Threading;
    
    namespace MultiThreadLockApplication
    {
    	class Student
    	{
    		private static string myTeacherName = "Bill";
    		private string myName = "Grace";
    		private static object somePrivateStaticObject = new Object();
    
    		public static string TeacherName
    		{
    			get
    			{
    				string theName;
    
    				// Synchronize access to the shared member.
    				lock(somePrivateStaticObject)
    				{
    					Console.WriteLine("Thread {0} starts to get the teacher's name",Thread.CurrentThread.GetHashCode());
    					theName = myTeacherName;
    
    					// Wait for 0.3 second.
    					Thread.Sleep(300);
    					Console.WriteLine("Thread {0} finished to get the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), theName);
    				}
    				return theName;
    			}
    
    			set
    			{
    				lock(somePrivateStaticObject)
    				{
    					Console.WriteLine("Thread {0} starts to set the teacher's name.", Thread.CurrentThread.GetHashCode());
    					myTeacherName = value;
    
    					// Wait for 0.3 second.
    					Thread.Sleep(300);
    					Console.WriteLine("Thread {0} finished to set the teacher's name:{1}.", Thread.CurrentThread.GetHashCode(), value);
    				}
    			}
    		}
    
    		public string GetName()
    		{
    			string theName;
    			lock(this)
    			{
    				Console.WriteLine("Thread {0} starts to get the student's name.", Thread.CurrentThread.GetHashCode());
    				theName = myName;
    
    				// Wait for 0.3 second.
    				Thread.Sleep(300);
    				Console.WriteLine("Thread {0} finished to get the student's name:{1}", Thread.CurrentThread.GetHashCode(), theName);
    				return theName;
    			}
    		}
    
    		public string SetName(string NewName)
    		{
    			string theOldName;
    			lock(this)
    			{
    				Console.WriteLine("Thread {0} starts to set the student's name.", Thread.CurrentThread.GetHashCode());
    				theOldName = myName;
    				myName = NewName;
    
    				// Wait for 0.3 second.
    				Thread.Sleep(300);
    				Console.WriteLine("Thread {0} finished to set the student's name:{1}", Thread.CurrentThread.GetHashCode(), NewName);
    			}
    			return theOldName;
    		}
    	}
    
    	class Class1
    	{
    		public static int WorkItemNum = 20;
    		public static AutoResetEvent Done = new AutoResetEvent(false);
    
    		public static void AccessClassResource(object state)
    		{
    			Random rnd = new Random();
    			string theName;
    			Student AStudent = (Student) state;
    
    			if( (rnd.Next() %2) != 0)
    			{
    				if( (rnd.Next() %2) != 0)
    				{
    					switch (rnd.Next() %3 )
    					{
    						case 0:
    							Student.TeacherName = "Tom";
    							break;
    						case 1:
    							Student.TeacherName = "Mike";
    							break;
    						case 2:
    							Student.TeacherName = "John";
    							break;
    					}
    				}
    				else
    				{
    					theName = Student.TeacherName;
    				}
    			}
    			else
    			{
    				if( (rnd.Next() %2) != 0)
    				{
    					switch (rnd.Next() %3 )
    					{
    						case 0:
    							AStudent.SetName("Janet");
    							break;
    						case 1:
    							AStudent.SetName("David");
    							break;
    						case 2:
    							AStudent.SetName("Ben");
    							break;
    					}
    				}
    				else
    				{
    					theName = AStudent.GetName();
    				}
    			}
    
    			if(Interlocked.Decrement( ref WorkItemNum) == 0)
    			{
    				Done.Set();
    			}
    		}
    
    		[STAThread]
    		static void Main(string[] args)
    		{
    			int threadNum;
    			Student AStudent = new Student();
    
    			// Queue up 20 work items in the ThreadPool.
    			for (threadNum = 0 ; threadNum <= WorkItemNum -1 ; threadNum++) 
    			{
    				ThreadPool.QueueUserWorkItem(new WaitCallback(AccessClassResource),AStudent);
    			}
    
    			Done.WaitOne();
    			Console.WriteLine("All operations have completed. Press enter to exit");
    			Console.ReadLine();
    		}
    	}
    }
  6. Erstellen Sie das Projekt und führen Sie die Anwendung aus.

Informationsquellen

Weitere Informationen finden Sie auf den folgenden MSDN-Websites (MSDN = Microsoft Developer Network):
Thread Pooling
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconthreadpooling.asp
ReaderWriterLock
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconreaderwriterlock.asp
ReaderWriterLock Class
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemThreadingReaderWriterLockClassTopic.asp?frame=true

Eigenschaften

Artikel-ID: 816161 - Geändert am: Montag, 17. November 2003 - Version: 1.1
Die Informationen in diesem Artikel beziehen sich auf:
  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
Keywords: 
kbthreadsync kbthread kbhowtomaster KB816161
Microsoft stellt Ihnen die in der Knowledge Base angebotenen Artikel und Informationen als Service-Leistung zur Verfügung. Microsoft übernimmt keinerlei Gewährleistung dafür, dass die angebotenen Artikel und Informationen auch in Ihrer Einsatzumgebung die erwünschten Ergebnisse erzielen. Die Entscheidung darüber, ob und in welcher Form Sie die angebotenen Artikel und Informationen nutzen, liegt daher allein bei Ihnen. Mit Ausnahme der gesetzlichen Haftung für Vorsatz ist jede Haftung von Microsoft im Zusammenhang mit Ihrer Nutzung dieser Artikel oder Informationen ausgeschlossen.

Ihr Feedback an uns

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com