HOWTO: Visual C# .NET을 사용하여 다중 스레딩 환경에서 공유 리소스에 대한 액세스 동기화

요약
Visual C# .NET 응용 프로그램에서 다중 스레딩을 사용하면 동시에 여러 가지 작업을 수행할 수 있습니다. 다중 스레딩은 다른 스레드를 여러 개 시작하여 동시에 다른 작업을 수행할 수 있습니다. 다중 스레딩은 응용 프로그램의 성능과 응답 능력도 향상시킵니다.

여러 스레드가 한 리소스에 동시에 액세스할 수 있기 때문에 개별 스레드를 프로그램의 다른 부분과 동기화할 수 있습니다. 이 문서에서는 다중 스레딩 프로그래밍을 사용할 경우의 몇 가지 일반적인 시나리오를 설명하고, 여러 스레드 간에 공유 리소스에 대한 액세스를 동기화하는 방법을 설명합니다.

맨 위로

다중 스레드 환경에서 모듈의 전역 데이터를 보호하는 방법에 대한 도움말

메서드 내의 public 필드는 응용 프로그램 내의 모든 스레드가 액세스할 수 있습니다. public 필드에 대한 액세스를 동기화하는 데 필드 대신 속성을 사용하고 ReaderWriterLock 개체를 사용하여 액세스를 제어할 수 있습니다. 이렇게 하려면 다음과 같이 하십시오.
  1. Visual Studio .NET을 시작합니다.
  2. 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 누릅니다.
  3. 프로젝트 형식에서 Visual C# 프로젝트를 누른 다음 템플릿에서 콘솔 응용 프로그램을 누릅니다.
  4. 이름 텍스트 상자에 MultiThreadApplication을 입력한 다음 확인을 누릅니다.
  5. 기존 코드를 Class1.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 문으로 표현되는 잠금을 사용하면 단일 실행 스레드가 개체에 대해 배타적인 실행 권한을 얻을 수 있습니다. 다음 예제는 잠금을 설명합니다.
  1. Visual Studio .NET을 엽니다.
  2. 파일 메뉴에서 새로 만들기를 가리킨 다음 프로젝트를 누릅니다.
  3. 프로젝트 형식에서 Visual C# 프로젝트를 누른 다음 템플릿에서 콘솔 응용 프로그램을 누릅니다.
  4. 이름 텍스트 상자에 MultiThreadLockApplication을 입력한 다음 확인을 누릅니다.
  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. 프로젝트를 빌드한 다음 응용 프로그램을 실행합니다.
맨 위로
참조
자세한 내용은 다음 MSDN(Microsoft Developer Network) 웹 사이트를 참조하십시오.맨 위로



Microsoft 제품 관련 기술 전문가들과 온라인으로 정보를 교환하시려면 Microsoft 뉴스 그룹에 참여하시기 바랍니다.
속성

문서 ID: 816161 - 마지막 검토: 09/18/2003 18:22:02 - 수정: 1.1

Microsoft Visual C# .NET 2003 Standard Edition, Microsoft Visual C# .NET 2002 Standard Edition

  • kbthreadsync kbthread kbhowtomaster KB816161
피드백