Как синхронизировать доступ к общему ресурсу в среде многопоточность с использованием Visual C#

Переводы статьи Переводы статьи
Код статьи: 816161 - Vizualiza?i produsele pentru care se aplic? acest articol.
Развернуть все | Свернуть все

В этой статье

Аннотация

Чтобы выполнять несколько задач в приложениях Microsoft Visual C# в то же время, используя многопоточность. Использование нескольких потоков для запуска различных потоков для выполнения различных задач, в то же время. Многопотоковость также повышает производительность и быстродействие приложения.

Поскольку несколько потоков могут обращаться к ресурсу одновременно, может потребоваться синхронизация отдельных потоков с другими частями программы. В этой статье собраны типовые сценарии, многопоточность по программированию и описание для синхронизации доступа к общим ресурсам нескольких потоков.

Чтобы защитить глобальные данные в модулях в многопотоковой среде

Открытые поля в методы доступны для всех потоков в приложении. Для синхронизации доступа к открытым полям, можно использовать свойства вместо поля и использоватьReaderWriterLockобъект для управления доступом. Выполните следующие действия::
  1. Запустите Microsoft Visual Studio.
  2. в менюФайл:Выберите пункт менюСОЗДАТЬ.и выберите командуProject.
  3. затем –Проекты Visual C#Из спискаТипы проектови выберите командуПриложение консолиИз спискаШаблоны:.

    Примечание.В Visual Studio 2005 или Visual Studio 2008 нажмите кнопкуВ Visual C#Из спискаТипы проектови выберите командуПриложение консолиИз спискаШаблоны:.
  4. В диалоговом окнеИМЯтекстовое поле, типMultiThreadApplicationи выберите командуOk..
  5. Замените существующий код на следующий код в класс Class1.cs.

    Примечание.В Visual Studio 2005 и Visual Studio 2008 по умолчанию файл имеет Program.cs.
    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. Построение проекта, а затем запустить приложение.

Чтобы создать свой класс поточно ориентированных

Несколько потоков могут попытаться получить доступ к объекту, в то же время. Если несколько потоков пытаются получить доступ к объекту в то же время, если другой поток изменяет ресурс, в то же время некоторые потоки может появиться недопустимом состоянии. Например если поток считывает поля объекта, в то время как другой поток изменение поля, первый поток может появиться недопустимое состояние поля. Такая ситуация называется состязания.

Во избежание такой ситуации может помочь защитить важные части кода от конкуренции, используя блокировки. Блокировки, представленной в Visual C# ключевое слово lock Statement, позволяет одному потоку выполнения, чтобы получить права на монопольный выполнение для объекта. Ниже примера демонстрируют блокировки:
  1. Откройте Visual Studio.
  2. в менюФайл:Выберите пункт менюСОЗДАТЬ.и выберите командуProject.
  3. затем –Проекты Visual C#Из спискаТипы проектови выберите командуПриложение консолиИз спискаШаблоны:.

    Примечание.В Visual Studio 2005 или Visual Studio 2008 нажмите кнопкуВ Visual C#Из спискаТипы проектови выберите командуПриложение консолиИз спискаШаблоны:.
  4. В диалоговом окнеИМЯтекстовое поле, типMultiThreadLockApplicationи выберите командуOk..
  5. Замените существующий код в класс Class1.cs следующий код:
    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. Построение проекта, а затем запустить приложение.

Ссылки

Дополнительные сведения см. на следующих страницах веб-узла Microsoft Developer Network (MSDN).:
Потоков пула
.aspx HTTP://msdn2.Microsoft.com/en-us/library/0ka9477y (vs.71)
ReaderWriterLock
.aspx HTTP://msdn2.Microsoft.com/en-us/library/bz6sth95 (vs.71)
Класс ReaderWriterLock
.aspx HTTP://msdn2.Microsoft.com/en-us/library/System.Threading.ReaderWriterLock (vs.71)

Свойства

Код статьи: 816161 - Последний отзыв: 25 ноября 2010 г. - Revision: 2.0
Информация в данной статье относится к следующим продуктам.
  • Microsoft Visual C# 2008 Express Edition
  • Microsoft Visual C# 2005 Express Edition
  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
Ключевые слова: 
kbthreadsync kbthread kbhowtomaster kbmt KB816161 KbMtru
Переведено с помощью машинного перевода
ВНИМАНИЕ! Перевод данной статьи был выполнен не человеком, а с помощью программы машинного перевода, разработанной корпорацией Майкрософт. Корпорация Майкрософт предлагает вам статьи, переведенные как людьми, так и средствами машинного перевода, чтобы у вас была возможность ознакомиться со статьями базы знаний KB на родном языке. Однако машинный перевод не всегда идеален. Он может содержать смысловые, синтаксические и грамматические ошибки, подобно тому как иностранец делает ошибки, пытаясь говорить на вашем языке. Корпорация Майкрософт не несет ответственности за неточности, ошибки и возможный ущерб, причиненный в результате неправильного перевода или его использования. Корпорация Майкрософт также часто обновляет средства машинного перевода.
Эта статья на английском языке:816161

Отправить отзыв

 

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