現在オフラインです。再接続するためにインターネットの接続を待っています

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 と入力し、[OK] をクリックします。
  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. プロジェクトをビルドし、アプリケーションを実行します。
先頭に戻る

クラスをスレッド セーフにする

複数のスレッドが 1 つのオブジェクトに同時にアクセスすることがあります。その場合、あるスレッドによってリソースに変更が加えられると、他のスレッドが取得した内容が無効になる場合があります。たとえば、あるスレッドがオブジェクトのフィールドを変更中に、他のスレッドがそのフィールドを読み取ると、後者のスレッドが取得したフィールドの状態が無効な場合があります。この状態を競合状態と呼びます。

この状態の発生を回避するには、ロックを使用して、競合状態からコードのクリティカル セクションを保護します。Visual C# キーワードの lock ステートメントでロックを使用すると、1 つの実行スレッドがオブジェクトの排他的実行の権利を取得できます。以下に、ロックを使用する手順の例を示します。
  1. Visual Studio .NET または Visual Studio 2005 を起動します。
  2. [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
  3. [プロジェクトの種類] ボックスの一覧の [Visual C# プロジェクト] をクリックし、[テンプレート] ボックスの一覧の [コンソール アプリケーション] をクリックします。

    : Visual Studio 2005 では、[プロジェクトの種類] ボックスの一覧の [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. プロジェクトをビルドし、アプリケーションを実行します。
先頭に戻る
関連情報
詳細については、以下の MSDN (Microsoft Developer Network) Web サイトを参照してください。先頭に戻る
プロパティ

文書番号:816161 - 最終更新日: 10/04/2006 00:08:24 - リビジョン: 2.2

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

  • kbthreadsync kbthread kbhowtomaster KB816161
フィードバック
getElementsByTagName("head")[0].appendChild(m); //c.microsoft.com/ms.js'><\/script>"); >