How to synchronize access to a shared resource in a multithreading environment by using Visual C# .NET or Visual C# 2005 (816161)
The information in this article applies to:
- Microsoft Visual C# 2005, Express Edition
- Microsoft Visual C# .NET (2003)
- Microsoft Visual C# .NET (2002)
For a Microsoft Visual Basic .NET version of this article, see 316136.
IN THIS TASKSUMMARYYou can perform multiple tasks in Microsoft Visual C# .NET or in Microsoft Visual C# 2005 applications at the same time by using multithreading. Multithreading can start different threads
to complete different tasks at the same time. Multithreading also improves the performance and
responsiveness of your applications. Because multiple threads can
access a resource at the same time, you may want to synchronize individual
threads with other parts of your program. This article describes some common
scenarios with multithreading programming, and explains how to synchronize the
access to a shared resource among the multiple threads. back to the topHelp to Protect Your Global Data in Modules in a Multithreaded Environment The public fields in methods are accessible to all the threads in
your application. To synchronize the access to the public fields, you can use
property instead of field, and use a ReaderWriterLock object to control the access. To do this, follow these steps:
- Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.
- On the File menu, point to New, and then click Project.
- Click
Visual C# Projects under Project Types, and
then click Console Application under
Templates.
Note In Visual Studio 2005, click Visual C# under Project Types, and
then click Console Application under
Templates. - In the Name text box, type
MultiThreadApplication, and then click
OK.
- Replace the existing code with the following code in
Class1.cs.
Note In Visual Studio 2005, the default file is 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;
}
}
}
}
- Build the project, and then run the application.
back to the topHelp to Make Your Class Thread-Safe Multiple threads may try to access an object at the same
time. When more than one thread competes for access to an
object at the same time, some threads may receive an invalid state if another
thread modifies the resource at the same time. For example, if a thread
reads the field of the object while another thread is modifying the field,
the first thread may receive an invalid state of the field. This situation is
named a race condition. To avoid this situation, you can help to protect
critical sections of your code from race conditions by using locks. A lock,
represented by the Visual C# keyword lock Statement, allows a single thread of
execution to obtain exclusive execution rights on an object. The following
example steps demonstrate locks:
- Open Visual Studio .NET or Visual Studio 2005.
- On the File menu, point to New, and then click Project.
- Click
Visual C# Projects under Project Types, and
then click Console Application under
Templates.
Note In Visual Studio 2005, click Visual C# under Project Types, and
then click Console Application under
Templates. - In the Name text box, type
MultiThreadLockApplication, and then click
OK.
- Replace the existing code with the following code in
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();
}
}
} - Build the project, and then run the application.
back to the
topREFERENCESFor more information, see the
following Microsoft Developer Network (MSDN) Web sites: back to the
top
Modification Type: | Major | Last Reviewed: | 1/19/2006 |
---|
Keywords: | kbThreadSync kbThread kbHOWTOmaster KB816161 kbAudDeveloper |
---|
|
|
©2004 Microsoft Corporation. All rights reserved.
|
|