readerwriterlock.cs

来自「没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没的 没」· CS 代码 · 共 622 行

CS
622
字号
/* * ReaderWriterLock.cs - Implementation of the *		"System.Threading.ReaderWriterLock" class. * * Copyright (C) 2003  Southern Storm Software, Pty Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */namespace System.Threading{#if !ECMA_COMPATpublic sealed class ReaderWriterLock{	// Lock information for a thread.	private sealed class LockInfo	{		public LockInfo next;		public Thread thread;		public int numReadLocks;		public int numWriteLocks;		public LockInfo(Thread thread, LockInfo next)				{					this.next = next;					this.thread = thread;					this.numReadLocks = 0;					this.numWriteLocks = 0;				}	}; // class LockInfo	// Internal state.	private int numReadLocks;	private int numWriteLocks;	private int seqNum;	private int lastWriteSeqNum;	private LockInfo lockList;	// Constructor.	public ReaderWriterLock()			{				numReadLocks = 0;				numWriteLocks = 0;				seqNum = 0;				lastWriteSeqNum = -1;				lockList = null;			}	// Get the lock information for the current thread.	private LockInfo GetLockInfo()			{				Thread thread = Thread.CurrentThread;				LockInfo info = lockList;				while(info != null)				{					if(info.thread == thread)					{						return info;					}					info = info.next;				}				return null;			}	// Get the lock information for the current thread, creating	// a new information object if one doesn't exist yet.	private LockInfo GetOrCreateLockInfo()			{				Thread thread = Thread.CurrentThread;				LockInfo info = lockList;				while(info != null)				{					if(info.thread == thread)					{						return info;					}					info = info.next;				}				info = new LockInfo(thread, lockList);				lockList = info;				return info;			}	// Acquire the read lock.	public void AcquireReaderLock(int millisecondsTimeout)			{				if(millisecondsTimeout < -1)				{					throw new ArgumentOutOfRangeException						("millisecondsTimeout",						 _("ArgRange_NonNegOrNegOne"));				}				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetOrCreateLockInfo();					// Block if some other thread has the writer lock.					if(millisecondsTimeout == -1)					{						while(info.numWriteLocks == 0 && numWriteLocks > 0)						{							if(!Monitor.Wait(this))							{								return;							}						}					}					else					{						DateTime expire = DateTime.UtcNow +							new TimeSpan(millisecondsTimeout *										 TimeSpan.TicksPerMillisecond);						DateTime now;						int ms;						while(info.numWriteLocks == 0 && numWriteLocks > 0)						{							now = DateTime.UtcNow;							if(now >= expire)							{								return;							}							ms = (int)((expire - now).Ticks /										TimeSpan.TicksPerMillisecond);							if(!Monitor.Wait(this, ms))							{								return;							}						}					}					// Update the thread and global read lock counts.					++(info.numReadLocks);					++numReadLocks;				}			}	public void AcquireReaderLock(TimeSpan timeout)			{				AcquireReaderLock(Monitor.TimeSpanToMS(timeout));			}	// Acquire the write lock.	public void AcquireWriterLock(int millisecondsTimeout)			{				if(millisecondsTimeout < -1)				{					throw new ArgumentOutOfRangeException						("millisecondsTimeout",						 _("ArgRange_NonNegOrNegOne"));				}				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetOrCreateLockInfo();					// Bail out early if we already have the writer lock.					if(info.numWriteLocks > 0)					{						++(info.numWriteLocks);						++numWriteLocks;						lastWriteSeqNum = ++seqNum;						return;					}					// Block while some other thread has the read or write lock.					if(millisecondsTimeout == -1)					{						while(numReadLocks > 0 || numWriteLocks > 0)						{							if(!Monitor.Wait(this))							{								return;							}						}					}					else					{						DateTime expire = DateTime.UtcNow +							new TimeSpan(millisecondsTimeout *										 TimeSpan.TicksPerMillisecond);						DateTime now;						int ms;						while(numReadLocks > 0 || numWriteLocks > 0)						{							now = DateTime.UtcNow;							if(now >= expire)							{								return;							}							ms = (int)((expire - now).Ticks /										TimeSpan.TicksPerMillisecond);							if(!Monitor.Wait(this, ms))							{								return;							}						}					}					// Update the thread and global write lock counts.					++(info.numWriteLocks);					++numWriteLocks;					lastWriteSeqNum = ++seqNum;				}			}	public void AcquireWriterLock(TimeSpan timeout)			{				AcquireWriterLock(Monitor.TimeSpanToMS(timeout));			}	// Determine if there have been any writers since a particular seqnum.	public bool AnyWritersSince(int seqNum)			{				lock(this)				{					if(seqNum >= 0 && seqNum < lastWriteSeqNum)					{						return true;					}					else					{						return false;					}				}			}	// Downgrade the current thread from a writer lock.	public void DowngradeFromWriterLock(ref LockCookie lockCookie)			{				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetLockInfo();					if(info == null)					{						return;					}					// Bail out if the cookie is not "Upgrade".					if(lockCookie.type != LockCookie.CookieType.Upgrade ||					   lockCookie.thread != Thread.CurrentThread)					{						return;					}					// Restore the thread to its previous lock state.					RestoreLockState(info, lockCookie.readCount,									 lockCookie.writeCount);				}			}	// Release all locks for the current thread and save them.	public LockCookie ReleaseLock()			{				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetLockInfo();					if(info == null)					{						return new LockCookie							(LockCookie.CookieType.None,							 Thread.CurrentThread, 0, 0);					}					// Bail out if the thread doesn't have any locks.					if(info.numReadLocks == 0 && info.numWriteLocks == 0)					{						return new LockCookie							(LockCookie.CookieType.None,							 Thread.CurrentThread, 0, 0);					}					// Copy the lock infomation into the cookie.					LockCookie cookie = new LockCookie						(LockCookie.CookieType.Saved,						 Thread.CurrentThread,						 info.numReadLocks, info.numWriteLocks);					// Release the active locks.					numReadLocks -= info.numReadLocks;					numWriteLocks -= info.numWriteLocks;					info.numReadLocks = 0;					info.numWriteLocks = 0;					// Determine if we need to wake up a waiting thread.					if(numReadLocks == 0 || numWriteLocks == 0)					{						Monitor.Pulse(this);					}					// Return the cookie to the caller.					return cookie;				}			}	// Release the read lock.	public void ReleaseReaderLock()			{				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetLockInfo();					if(info == null)					{						return;					}					// Save the global write lock count.					int saveRead = numReadLocks;					int saveWrite = numWriteLocks;					// Update the thread and global lock count values.					if(info.numReadLocks > 0)					{						--(info.numReadLocks);						--numReadLocks;					}					// Determine if we need to wake up a waiting thread.					if(saveRead > numReadLocks && numReadLocks == 0)					{						Monitor.Pulse(this);					}					else if(saveWrite > numWriteLocks && numWriteLocks == 0)					{						Monitor.Pulse(this);					}				}			}	// Release the write lock.	public void ReleaseWriterLock()			{				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetLockInfo();					if(info == null)					{						return;					}					// Bail out with an exception if we have read locks.					if(info.numReadLocks > 0)					{						throw new ApplicationException(_("Invalid_RWLock"));					}					// Update the thread and global lock count values.					if(info.numWriteLocks == 0)					{						return;					}					--(info.numWriteLocks);					--numWriteLocks;					// Determine if we need to wake up a waiting thread.					if(numWriteLocks == 0)					{						Monitor.Pulse(this);					}				}			}	// Restore the lock state for the current thread.	private void RestoreLockState(LockInfo info, int readCount, int writeCount)			{				// Save the current global lock state.				int saveRead = numReadLocks;				int saveWrite = numWriteLocks;				// Remove the locks that are currently held by the thread.				numReadLocks -= info.numReadLocks;				numWriteLocks -= info.numWriteLocks;				info.numReadLocks = 0;				info.numWriteLocks = 0;				// Wake up any waiting threads.				if(saveRead > numReadLocks && numReadLocks == 0)				{					Monitor.Pulse(this);				}				else if(saveWrite > numWriteLocks && numWriteLocks == 0)				{					Monitor.Pulse(this);				}				// Re-acquire the locks based upon the type required.				if(readCount > 0 && writeCount == 0)				{					// Re-acquire read locks only.					while(numWriteLocks > 0)					{						Monitor.Wait(this);					}					info.numReadLocks += readCount;					numReadLocks += readCount;				}				else if(readCount == 0 && writeCount > 0)				{					// Re-acquire write locks only.					while(numReadLocks > 0 && numWriteLocks > 0)					{						Monitor.Wait(this);					}					info.numWriteLocks += writeCount;					numWriteLocks += writeCount;				}				else if(readCount > 0 && writeCount > 0)				{					// Re-acquire both read and write locks.					while(numWriteLocks > 0)					{						Monitor.Wait(this);					}					info.numReadLocks += readCount;					numReadLocks += readCount;					info.numWriteLocks += writeCount;					numWriteLocks += writeCount;				}			}	// Restore all locks for the curent thread to a previous "Release" value.	public void RestoreLock(ref LockCookie lockCookie)			{				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetLockInfo();					if(info == null)					{						return;					}					// Bail out if the cookie is not "Saved" or if					// we have prevailing locks at the moment.					if(lockCookie.type != LockCookie.CookieType.Saved ||					   lockCookie.thread != Thread.CurrentThread ||					   info.numReadLocks > 0 ||					   info.numWriteLocks > 0)					{						return;					}					// Restore the thread to its previous lock state.					RestoreLockState(info, lockCookie.readCount,									 lockCookie.writeCount);				}			}	// Update the current thread to a writer lock.	public LockCookie UpgradeToWriterLock(int millisecondsTimeout)			{				LockCookie cookie;				if(millisecondsTimeout < -1)				{					throw new ArgumentOutOfRangeException						("millisecondsTimeout",						 _("ArgRange_NonNegOrNegOne"));				}				lock(this)				{					// Get the lock information for this thread.					LockInfo info = GetOrCreateLockInfo();					// Bail out early if we already have the writer lock.					if(info.numWriteLocks > 0)					{						cookie = new LockCookie							(LockCookie.CookieType.Upgrade,							 Thread.CurrentThread,							 info.numReadLocks, info.numWriteLocks);						++(info.numWriteLocks);						++numWriteLocks;						lastWriteSeqNum = ++seqNum;						return cookie;					}					// If we have the read lock, then upgrade it.					if(info.numReadLocks > 0)					{						cookie = new LockCookie							(LockCookie.CookieType.Upgrade,							 Thread.CurrentThread,							 info.numReadLocks, info.numWriteLocks);						info.numWriteLocks += info.numReadLocks;						numReadLocks -= info.numReadLocks;						numWriteLocks -= info.numReadLocks;						info.numReadLocks = 0;						lastWriteSeqNum = ++seqNum;						return cookie;					}					// Block while some other thread has the read or write lock.					if(millisecondsTimeout == -1)					{						while(numReadLocks > 0 || numWriteLocks > 0)						{							if(!Monitor.Wait(this))							{								return new LockCookie									(LockCookie.CookieType.None,									 Thread.CurrentThread, 0, 0);							}						}					}					else					{						DateTime expire = DateTime.UtcNow +							new TimeSpan(millisecondsTimeout *										 TimeSpan.TicksPerMillisecond);						DateTime now;						int ms;						while(numReadLocks > 0 || numWriteLocks > 0)						{							now = DateTime.UtcNow;							if(now >= expire)							{								return new LockCookie									(LockCookie.CookieType.None,									 Thread.CurrentThread, 0, 0);							}							ms = (int)((expire - now).Ticks /										TimeSpan.TicksPerMillisecond);							if(!Monitor.Wait(this, ms))							{								return new LockCookie									(LockCookie.CookieType.None,									 Thread.CurrentThread, 0, 0);							}						}					}					// Update the thread and global write lock counts.					cookie = new LockCookie						(LockCookie.CookieType.Upgrade,						 Thread.CurrentThread,						 info.numReadLocks, info.numWriteLocks);					++(info.numWriteLocks);					++numWriteLocks;					lastWriteSeqNum = ++seqNum;					return cookie;				}			}	public LockCookie UpgradeToWriterLock(TimeSpan timeout)			{				return UpgradeToWriterLock(Monitor.TimeSpanToMS(timeout));			}	// Determine if the read lock is held by the current thread.	public bool IsReaderLockHeld			{				get				{					lock(this)					{						LockInfo info = GetLockInfo();						if(info != null)						{							return (info.numReadLocks > 0);						}						else						{							return false;						}					}				}			}	// Determine if the write lock is held by the current thread.	public bool IsWriterLockHeld			{				get				{					lock(this)					{						LockInfo info = GetLockInfo();						if(info != null)						{							return (info.numWriteLocks > 0);						}						else						{							return false;						}					}				}			}	// Get the writer sequence number.	public int WriterSeqNum			{				get				{					lock(this)					{						return seqNum;					}				}			}}; // class ReaderWriterLock#endif // !ECMA_COMPAT}; // namespace System.Threading

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?