Synchronizing Access to Resources

General speaking, file system will lock the file when an application is accessing it. If another application wana access this file, it must wait for the lock to be released. In multithreaded programming, we face the same situation. However, to make it easy, .NET provide synchronization object to help us to do this task. There are four types of resources that we need to pay attendtion:

-System resources, like communication ports
-Resources shared by multiple process, like file handles
-The resources of a single application domain accessed by multiple threads, like global, static, and instance fields
-Objects instances that are accessed by multiple threads.

Monitor Class: is applied to lock objects. In C#, using keword lock to specify the object that you want to monitor.
1 public void Subtract()
2 {
3     lock (this)
4     {
5         result = value1 - value2;
6         Thread.Sleep(1000);
7         Console.WriteLine("Subtract: " + result);
8     }
9 }

When a Thread.Start(Subtract()) is called, other functions cannot access value1, value2, and result due to Subtract() is accessing these varialbes. In other words, this lock behavior prevents result value from being overwritten. Nevertheless, Monitor class does not lock value type, but only lock the reference type. Therefore, Monitor locks the object to which Subtract() belongs, not the result variables itself.

However, Monitor class does not separate read and write lock. Multiple threads might need to read value simultaneously. If using Monitor class, only one thread can read a file at a time, another one has to wait.

ReaderWriterLock, allowes more than one threads read file at same time. And this would be stopped if a thread begin to write to this file. 
       
 1 class MemFile
 2 {
 3     string file = "Hello, world!";
 4     ReaderWriterLock rwl = new ReaderWriterLock();
 5     public void ReadFile()
 6     {
 7         // Allow thread to continue only if no other thread
 8         // has a write lock
 9         rwl.AcquireReaderLock(10000);
10         for (int i = 1; i <= 3; i++)
11         {
12         Console.WriteLine(file);
13         Thread.Sleep(1000);
14         }
15         rwl.ReleaseReaderLock();
16     }
17     public void WriteFile()
18     {
19         // Allow thread to continue only if no other thread
20         // has a read or write lock
21         rwl.AcquireWriterLock(10000);
22         file += " It's a nice day!";
23         rwl.ReleaseWriterLock();
24     }
25 }

Interlocked Performing atomic operations (are static methods) in thread-safe way, which is an alternative to locking access to a resource.
 1 int num = 0;
 2 //num += 1
 3 Interlocked.Increment(ref num);
 4 //num -=1;
 5 Interlocked.Decrement(ref num);
 6 //num += val2
 7 Interlocked.Add(ref num, 10);
 8 //Set the value of an object: num = 35
 9 Interlocked.Exchange(ref num, 35);
10 //if num == 75 then num = 35
11 Interlocked.CompareExchange(ref num, 7535);
12 //This is equivalent to reading a variable.
13 Interlocked.Read(ref num);

Increment an Integer in multithread application (2 threads) can cause some error if Interlocked.Increment() is not applied:
- Incrementing an Integer has 2 steps: 1, read the original value; 2, replace the value with newly incremented value.
- When Thread1 read the original value (i.e. 10) and then is interrupted by Thread2, Thread2 read the same original value (10) and replace with 11 (add 1).
- When Thread2 finished, Thread1 still process the original value as it was before Thread2 updated it, so it is still 10, and then rewrite the value with 11.
- Therefore, two threads cause only 1 increment, which is actually expected to cause 2 increments.

Using Interlocked.Increment(ref num) can avoid this error. Because it does not allow another thread to interrupt the increment operation.
posted @ 2009-08-19 14:28  我写的不是代码 是寂寞  阅读(403)  评论(0编辑  收藏  举报