C#多线程编程实例实战.docx

上传人:b****7 文档编号:10208848 上传时间:2023-02-09 格式:DOCX 页数:10 大小:99.51KB
下载 相关 举报
C#多线程编程实例实战.docx_第1页
第1页 / 共10页
C#多线程编程实例实战.docx_第2页
第2页 / 共10页
C#多线程编程实例实战.docx_第3页
第3页 / 共10页
C#多线程编程实例实战.docx_第4页
第4页 / 共10页
C#多线程编程实例实战.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

C#多线程编程实例实战.docx

《C#多线程编程实例实战.docx》由会员分享,可在线阅读,更多相关《C#多线程编程实例实战.docx(10页珍藏版)》请在冰豆网上搜索。

C#多线程编程实例实战.docx

C#多线程编程实例实战

C#多线程编程实例实战

C#多线程编程实例实战

问题的提出

  所谓单个写入程序/多个阅读程序的线程同步问题,是指任意数量的线程访问共享资源时,写入程序(线程)需要修改共享资源,而阅读程序(线程)需要读取数据。

在这个同步问题中,很容易得到下面二个要求:

  1)当一个线程正在写入数据时,其他线程不能写,也不能读。

  2)当一个线程正在读入数据时,其他线程不能写,但能够读。

  在数据库应用程序环境中经常遇到这样的问题。

比如说,有n个最终用户,他们都要同时访问同一个数据库。

其中有m个用户要将数据存入数据库,n-m个用户要读取数据库中的记录。

{

//m_mutext很快可以得到,以便进入临界区

m_mutex.WaitOne();

//是否有写入线程存在

boolbExistingWriter=(m_nActive<0);

if(bExistingWriter)

{//等待阅读线程数目加1,当有锁释放时,根据此数目来调度线程

m_nWaitingReaders++;

}

else

{//当前活动线程加1

m_nActive++;

}

m_mutex.ReleaseMutex();

//存储锁标志为Reader

System.LocalDataStoreSlotslot=Thread.GetNamedDataSlot(m_strThreadSlotName);

objectobj=Thread.GetData(slot);

LockFlagsflag=LockFlags.None;

if(obj!

=null)

flag=(LockFlags)obj;

if(flag==LockFlags.None)

{

Thread.SetData(slot,LockFlags.Reader);

}

else

{

Thread.SetData(slot,(LockFlags)((int)flag|(int)LockFlags.Reader));

}

 

if(bExistingWriter)

{//等待指定的时间

this.m_aeReaders.WaitOne(millisecondsTimeout,true);

}

}

  它首先进入临界区(用以在多线程环境下保证活动线程数目的操作的正确性)判断当前活动线程的数目,如果有写线程(m_nActive<0)存在,则等待指定的时间并且等待的阅读线程数目加1。

如果当前活动线程是读线程(m_nActive>=0),则可以让读线程继续运行。

  申请写入锁的函数原型为:

publicvoidAcquireWriterLock(intmillisecondsTimeout),其中的参数为等待调度的时间。

函数定义如下:

publicvoidAcquireWriterLock(intmillisecondsTimeout)

{

//m_mutext很快可以得到,以便进入临界区

m_mutex.WaitOne();

//是否有活动线程存在

boolbNoActive=m_nActive==0;

if(!

bNoActive)

{

m_nWaitingWriters++;

}

else

{

m_nActive--;

}

m_mutex.ReleaseMutex();

//存储线程锁标志

System.LocalDataStoreSlotslot=Thread.GetNamedDataSlot("myReaderWriterLockDataSlot");

objectobj=Thread.GetData(slot);

LockFlagsflag=LockFlags.None;

if(obj!

=null)

flag=(LockFlags)Thread.GetData(slot);

if(flag==LockFlags.None)

{

Thread.SetData(slot,LockFlags.Writer);

}

else

{

Thread.SetData(slot,(LockFlags)((int)flag|(int)LockFlags.Writer));

}

//如果有活动线程,等待指定的时间

if(!

bNoActive)

this.m_aeWriters.WaitOne(millisecondsTimeout,true);

}

  它首先进入临界区判断当前活动线程的数目,如果当前有活动线程存在,不管是写线程还是读线程(m_nActive),线程将等待指定的时间并且等待的写入线程数目加1,否则线程拥有写的权限。

  释放阅读锁的函数原型为:

publicvoidReleaseReaderLock()。

函数定义如下:

publicvoidReleaseReaderLock()

{

System.LocalDataStoreSlotslot=Thread.GetNamedDataSlot(m_strThreadSlotName);

LockFlagsflag=(LockFlags)Thread.GetData(slot);

if(flag==LockFlags.None)

{

return;

}

boolbReader=true;

switch(flag)

{

caseLockFlags.None:

break;

caseLockFlags.Writer:

bReader=false;

break;

}

if(!

bReader)

return;

Thread.SetData(slot,LockFlags.None);

m_mutex.WaitOne();

AutoResetEventautoresetevent=null;

this.m_nActive--;

if(this.m_nActive==0)

{

if(this.m_nWaitingReaders>0)

{

m_nActive++;

m_nWaitingReaders--;

autoresetevent=this.m_aeReaders;

}

elseif(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等于整个等待的阅读线程数目。

测试

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

测试程序如下,

usingSystem;

usingSystem.Threading;

usingMyThreading;

classResource{

myReaderWriterLockrwl=newmyReaderWriterLock();

publicvoidRead(Int32threadNum){

rwl.AcquireReaderLock(Timeout.Infinite);

try{

Console.WriteLine("StartResourcereading(Thread={0})",threadNum);

Thread.Sleep(250);

Console.WriteLine("StopResourcereading(Thread={0})",threadNum);

}

finally{

rwl.ReleaseReaderLock();

}

}

publicvoidWrite(Int32threadNum){

rwl.AcquireWriterLock(Timeout.Infinite);

try{

Console.WriteLine("StartResourcewriting(Thread={0})",threadNum);

Thread.Sleep(750);

Console.WriteLine("StopResourcewriting(Thread={0})",threadNum);

}

finally{

rwl.ReleaseWriterLock();

}

}

}

classApp{

staticInt32numAsyncOps=20;

staticAutoResetEventasyncOpsAreDone=newAutoResetEvent(false);

staticResourceres=newResource();

 

publicstaticvoidMain(){

for(Int32threadNum=0;threadNum<20;threadNum++){

ThreadPool.QueueUserWorkItem(newWaitCallback(UpdateResource),threadNum);

}

asyncOpsAreDone.WaitOne();

Console.WriteLine("Alloperationshavecompleted.");

Console.ReadLine();

}

//Thecallbackmethod'ssignatureMUSTmatchthatofaSystem.Threading.TimerCallback

//delegate(ittakesanObjectparameterandreturnsvoid)

staticvoidUpdateResource(Objectstate){

Int32threadNum=(Int32)state;

if((threadNum%2)!

=0)res.Read(threadNum);

elseres.Write(threadNum);

if(Interlocked.Decrement(refnumAsyncOps)==0)

asyncOpsAreDone.Set();

}

}

  从测试结果中可以看出,可以满足单个写入程序\多个阅读程序的实现要求。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 其它课程

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1