C# Monitor类的使用
C#中, 通过System.Threading.Monitor类可以实现多线程中对某些代码块的同步访问,以确保数据的安全性。
object obj=new object();
Monitor在锁对象obj上会维持两个线程队列R和W以及一个引用T :
(1) T是对当前获得了obj锁的线程的引用(设此线程为CurrThread);
(2) R为就绪队列,其上的线程已经准备好获取obj锁。当obj锁被CurrThread释放后(CurrThread可通过Monitor.Exit(obj)或Monitor.Wait(obj)来释放其所获的obj锁)这些线程就会去竞争obj锁,获得obj锁的线程将被T引用; 线程调用Monitor.Enter(obj)或Monitor.TryEnter(obj)将会使该线程直接进入R队列。
(3) W为等待队列,其上的线程是因为调用了Monitor.Wait(obj)而进入W队列的;W上的线程不会被OS直接调度执行,也就是说它们没有准备好获取obj锁,就是说在等待队列上的线程不能去获得obj锁。当前获得obj锁的线程CurrThread调用Monitor.Pulse(obj)或Monitor.PulseAll(obj)后会使W队列中的第一个等待线程或所有等待线程被移至R队列,这时被移至R队列的这些线程就有机会被OS直接调度执行,也就是有可以去竞争obj锁。
Monitor类中的重要方法:
方法名称描述
void Enter(object obj)Acquires an exclusive lock on the specified object.void Enter(object obj, ref bool lockTaken)Acquires an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken.void Exit(object obj)Releases an exclusive lock on the specified object.void Pulse(object obj)Notifies a thread in the waiting queue of a change in the locked object's state.void PulseAll(object obj)Notifies all waiting threads of a change in the object's state.bool TryEnter(object obj)Attempts to acquire an exclusive lock on the specified object.bool TryEnter(object obj, int millisecondsTimeout)Attempts, for the specified number of milliseconds, to acquire an exclusive lock on the specified object.bool Wait(object obj)Releases the lock on an object and blocks the current thread until it reacquires
the lock. If the specified time-out interval elapses, the thread enters the ready queue.
例子1:
privateobjectlockObj=newobject();privatevoidExecute(){Monitor.Enter(lockObj);for(inti=0;i<5;i++){Console.WriteLine("ThreadName:"+Thread.CurrentThread.Name+",Count:"+i);Thread.Sleep(newRandom().Next(5000));}Monitor.Exit(lockObj);}publicvoidTest(){Threadthread1=newThread(newThreadStart(Execute));thread1.Name="Thread1";thread1.Start();Threadthread2=newThread(newThreadStart(Execute));thread2.Name="Thread2";thread2.Start();thread1.Join();thread2.Join();}
输出结果:
Thread Name:Thread1, Count:0
Thread Name:Thread1, Count:1
Thread Name:Thread1, Count:2
Thread Name:Thread1, Count:3
Thread Name:Thread1, Count:4
Thread Name:Thread2, Count:0
Thread Name:Thread2, Count:1
Thread Name:Thread2, Count:2
Thread Name:Thread2, Count:3
Thread Name:Thread2, Count:4
例子2:
privatevoidExecute1(){if(Monitor.TryEnter(lockObj,1000)){for(inti=0;i<5;i++){Console.WriteLine("ThreadName:"+Thread.CurrentThread.Name+",Count:"+i);Thread.Sleep(newRandom().Next(5000));}Monitor.Exit(lockObj);}}publicvoidTest1(){Threadthread1=newThread(newThreadStart(Execute1));thread1.Name="Thread1";thread1.Start();Threadthread2=newThread(newThreadStart(Execute1));thread2.Name="Thread2";thread2.Start();thread1.Join();thread2.Join();}
输出结果:
Thread Name:Thread1, Count:0
Thread Name:Thread1, Count:1
Thread Name:Thread1, Count:2
Thread Name:Thread1, Count:3
Thread Name:Thread1, Count:4
因为Thread2尝试获取锁失败,所以没有执行锁内部的代码块。
例子3:
privateQueuequeue=newQueue();publicvoidSendThread(){intcounter=0;lock(queue){while(counter<5){//Wait,ifthequeueisbusy.Monitor.Wait(queue);//Pushoneelement.queue.Enqueue(counter);//Releasethewaitingthread.Monitor.Pulse(queue);counter++;}}}publicvoidConsumeThread(){lock(queue){//Releasethewaitingthread.Monitor.Pulse(queue);//Waitintheloop,whilethequeueisbusy.//Exitonthetime-outwhenthefirstthreadstops.while(Monitor.Wait(queue,1000)){//Popthefirstelement.intcounter=(int)queue.Dequeue();//Printthefirstelement.Console.WriteLine("QueueValue:"+counter.ToString());//Releasethewaitingthread.Monitor.Pulse(queue);}}}publicvoidTest2(){Threadthread1=newThread(newThreadStart(SendThread));thread1.Name="Thread1";thread1.Start();Threadthread2=newThread(newThreadStart(ConsumeThread));thread2.Name="Thread2";thread2.Start();thread1.Join();thread2.Join();Console.WriteLine("QueueSize:"+queue.Count);}
输出结果:
Queue Value:0
Queue Value:1
Queue Value:2
Queue Value:3
Queue Value:4
Queue Size:0
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。