C#多线程编程实例实战(2)

释放阅读锁的函数原型为:public void ReleaseReaderLock()。函数定义如下:

public void ReleaseReaderLock()

{    
System.LocalDataStoreSlot slot = Thread.GetNamedDataSlot(m_strThreadSlotName ); 
LockFlags flag = (LockFlags)Thread.GetData( slot ); 
if( flag == LockFlags.None )

{   return; 
}

bool bReader = true;  switch( flag ) 
{    
case LockFlags.None:    
break; 
case LockFlags.Writer: 
bReader = false; 
break; 
}

if( !bReader ) 
return; 
Thread.SetData( slot, LockFlags.None ); 
m_mutex.WaitOne(); 
AutoResetEvent autoresetevent = null; 
this.m_nActive --; 
if( this.m_nActive == 0 ) 
{    if( this.m_nWaitingReaders > 0 )

{    
m_nActive ++ ;    
m_nWaitingReaders --;    
autoresetevent = this.m_aeReaders; 
}    
else if( this.m_nWaitingWriters > 0)    
{   
m_nWaitingWriters--;

m_nActive --;

autoresetevent = this.m_aeWriters ;

}    }

m_mutex.ReleaseMutex();    
if( autoresetevent != null )    
autoresetevent.Set();    


释 放阅读锁时,首先判断当前线程是否拥有阅读锁(通过线程局部存储的标志),然后判断是否有等待的阅读线程,如果有,先将当前活动线程加1,等待阅读线程数 目减1,然后置事件为有信号。如果没有等待的阅读线程,判断是否有等待的写入线程,如果有则活动线程数目减1,等待的写入线程数目减1。释放写入锁与释放 阅读锁的过程基本一致,可以参看源代码。 

注意在程序中,释放锁时,只会唤醒一个阅读程序,这是因为使用AutoResetEvent的原历,读者可自行将其改成ManualResetEvent,同时唤醒多个阅读程序,此时应令m_nActive等于整个等待的阅读线程数目。

测试 

测试程序取自.Net FrameSDK中的一个例子,只是稍做修改。测试程序如下,

using System;    
using System.Threading;   
using MyThreading;    
class Resource {    
myReaderWriterLock rwl = new myReaderWriterLock();    
public void Read(Int32 threadNum) {    
rwl.AcquireReaderLock(Timeout.Infinite);

try {   Console.WriteLine("Start Resource reading (Thread={0})", threadNum);

Thread.Sleep(250);

Console.WriteLine("Stop Resource reading (Thread={0})", threadNum); 
}

finally {  rwl.ReleaseReaderLock();

}   }

public void Write(Int32 threadNum) {    
rwl.AcquireWriterLock(Timeout.Infinite);    
try {    
Console.WriteLine("Start Resource writing (Thread={0})", threadNum); 
Thread.Sleep(750); 
Console.WriteLine("Stop Resource writing (Thread={0})", threadNum); 
}

finally {  rwl.ReleaseWriterLock();    
}   }    
}    
class App {

static Int32 numAsyncOps = 20;    
static AutoResetEvent asyncOpsAreDone = new AutoResetEvent(false);    
static Resource res = new Resource();       
public static void Main() {    
for (Int32 threadNum = 0; threadNum < 20; threadNum++) {    
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateResource), threadNum);    
}

asyncOpsAreDone.WaitOne(); 
Console.WriteLine("All operations have completed.");    
Console.ReadLine();    
}

// The callback method's signature MUST match that of a System.Threading.TimerCallback    
// delegate (it takes an Object parameter and returns void)   
static void UpdateResource(Object state) {    
Int32 threadNum = (Int32) state;    
if ((threadNum % 2) != 0) res.Read(threadNum);    
else res.Write(threadNum);    
if (Interlocked.Decrement(ref numAsyncOps) == 0)    
asyncOpsAreDone.Set();    
}    
}

posted @ 2009-03-27 09:53  yongbin621  阅读(394)  评论(0编辑  收藏  举报