您目前已離線,請等候您的網際網路重新連線

如何使用 Visual C# .NET 或 Visual C# 2005 在多執行緒環境中同步化共用資源的存取

如需本文的 Microsoft Visual Basic .NET 版本,請參閱 316136

本文內容

結論
您可以使用多執行緒在 Microsoft Visual C# .NET 或 Microsoft Visual C# 2005 應用程式中同時執行多項工作。多執行緒可同時啟動不同的執行緒以完成不同的工作。多執行緒也可以改善應用程式的效能和回應。

由於多個執行緒可以同時存取資源,因此您可能會想要同步處理個別執行緒與程式的其他部分。本文將告訴您一些多執行緒程式設計會遇到的共同狀況,並說明如何同步處理多個執行緒之間對共享資源的存取。

回到頁首

在多執行緒環境協助保護模組中的全域資料

應用程式中的所有執行緒都可以存取方法中的公用欄位。如果要同步化對公用欄位的存取,您可以改用屬性,而不要使用欄位,並且使用 ReaderWriterLock 物件來控制存取。如果要執行這項操作,請依照下列步驟執行:
  1. 啟動 Microsoft Visual Studio .NET 或 Microsoft Visual Studio 2005。
  2. [檔案] 功能表上,指向 [新增],然後按一下 [專案]
  3. 按一下 [專案類型] 下的 [Visual C# 專案],然後按一下 [範本] 下的 [主控台應用程式]

    注意 在 Visual Studio 2005 中,按一下 [專案類型] 下的 [Visual C#],然後按一下 [範本] 下的 [主控台應用程式]
  4. [名稱] 文字方塊中,輸入 MultiThreadApplication,然後按一下 [確定]
  5. 以 Class1.cs 中的下列程式碼取代現有的程式碼。

    注意 在 Visual Studio 2005 中,預設檔案為 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# 的關鍵字鎖定陳述式表示,允許單一執行緒獨佔物件的執行權。下列範例步驟示範鎖定:
  1. 開啟 Visual Studio .NET 或 Visual Studio 2005。
  2. [檔案] 功能表上,指向 [新增],然後按一下 [專案]
  3. 按一下 [專案類型] 下的 [Visual C# 專案],然後按一下 [範本] 下的 [主控台應用程式]

    注意 在 Visual Studio 2005 中,按一下 [專案類型] 下的 [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. 建置專案,然後執行應用程式。
回到頁首
內容

文章識別碼:816161 - 最後檢閱時間:06/01/2007 03:16:25 - 修訂: 2.4

Microsoft Visual C# 2005 Express Edition, Microsoft Visual C# .NET 2003 標準版, Microsoft Visual C# .NET 2002 Standard Edition

  • kbthreadsync kbthread kbhowtomaster KB816161
意見反應
c="https://c.microsoft.com/ms.js">