C#创建安全的栈(Stack)存储结构
在C#中,用于存储的结构较多,如:DataTable,DataSet,List,Dictionary,Stack等结构,各种结构采用的存储的方式存在差异,效率也必然各有优缺点。现在介绍一种后进先出的数据结构。
谈到存储结构,我们在项目中使用的较多。对于Task存储结构,栈与队列是类似的结构,在使用的时候采用不同的方法。C#中栈(Stack)是编译期间就分配好的内存空间,因此你的代码中必须就栈的大小有明确的定义;堆是程序运行期间动态分配的内存空间,你可以根据程序的运行情况确定要分配的堆内存的大小。
在C#中,栈通常保存着我们代码执行的步骤。C#中的引用类型存储在栈中,在程序运行的时候,每个线程(Thread)都会维护一个自己的专属线程堆栈。当一个方法被调用的时候,主线程开始在所属程序集的元数据中,查找被调用方法,然后通过JIT即时编译并把结果(一般是本地CPU指令)放在栈顶。CPU通过总线从栈顶取指令,驱动程序以执行下去。
以上对栈这个数据结构进行了一个简单的介绍,现在看一下C#实现栈结构的底层方法:
///<summary> ///初始化<seecref="T:System.Collections.Generic.Stack`1"/>类的新实例,该实例为空并且具有默认初始容量。 ///</summary> [__DynamicallyInvokable] publicStack(); ///<summary> ///初始化<seecref="T:System.Collections.Generic.Stack`1"/>类的新实例,该实例为空,具有指定的初始容量或默认的初始容量(其中较大的一个)。 ///</summary> ///<paramname="capacity"><seecref="T:System.Collections.Generic.Stack`1"/>可包含的初始元素数。</param><exceptioncref="T:System.ArgumentOutOfRangeException"><paramrefname="capacity"/>islessthanzero.</exception> [__DynamicallyInvokable] publicStack(intcapacity); ///<summary> ///初始化<seecref="T:System.Collections.Generic.Stack`1"/>类的新实例,该实例包含从指定集合复制的元素并且具有足够的容量来容纳所复制的元素。 ///</summary> ///<paramname="collection">从中复制元素的集合。</param><exceptioncref="T:System.ArgumentNullException"><paramrefname="collection"/>isnull.</exception> [__DynamicallyInvokable] publicStack(IEnumerable<T>collection);
以上是对stack的部分方法的介绍,由于在操作数据存储的同时,会考虑到线程的安全性。
进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。线程分为前台线程和后台线程,通过Thread类新建线程默认为前台线程。当所有前台线程关闭时,所有的后台线程也会被直接终止,不会抛出异常。
接下来看一下ReaderWriterLockSlim类:
///<summary>
///表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。
///</summary>
[__DynamicallyInvokable]
[HostProtection(SecurityAction.LinkDemand,ExternalThreading=true,Synchronization=true)]
[HostProtection(SecurityAction.LinkDemand,MayLeakOnAbort=true)]
publicclassReaderWriterLockSlim:IDisposable
{
///<summary>
///使用默认属性值初始化<seecref="T:System.Threading.ReaderWriterLockSlim"/>类的新实例。
///</summary>
[__DynamicallyInvokable]
publicReaderWriterLockSlim();
///<summary>
///在指定锁定递归策略的情况下初始化<seecref="T:System.Threading.ReaderWriterLockSlim"/>类的新实例。
///</summary>
///<paramname="recursionPolicy">枚举值之一,用于指定锁定递归策略。</param>
[__DynamicallyInvokable]
publicReaderWriterLockSlim(LockRecursionPolicyrecursionPolicy);
///<summary>
///尝试进入读取模式锁定状态。
///</summary>
///<exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入读取的模式。-或-当它已经包含写入锁时,当前线程可能不会获取读的锁定。-或-递归数将超出该计数器的容量。此限制是很大的应用程序应永远不会遇到它。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicvoidEnterReadLock();
///<summary>
///尝试进入读取模式锁定状态,可以选择超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入读取模式,则为true;否则为false。
///</returns>
///<paramname="timeout">等待的间隔;或为-1毫秒,表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="timeout"/>为负数,但它不等于-1毫秒为单位),这是唯一允许的值为负。-或-值<paramrefname="timeout"/>大于<seecref="F:System.Int32.MaxValue"/>毫秒为单位)。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterReadLock(TimeSpantimeout);
///<summary>
///尝试进入读取模式锁定状态,可以选择整数超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入读取模式,则为true;否则为false。
///</returns>
///<paramname="millisecondsTimeout">等待的毫秒数,或为-1(<seecref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="millisecondsTimeout"/>为负数,但它不是等于<seecref="F:System.Threading.Timeout.Infinite"/>(-1),这是唯一允许的值为负。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterReadLock(intmillisecondsTimeout);
///<summary>
///尝试进入写入模式锁定状态。
///</summary>
///<exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已在任何模式下进入该锁。-或-当前线程已进入读取的模式,因此尝试进入锁定状态写模式,则会创建导致死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicvoidEnterWriteLock();
///<summary>
///尝试进入写入模式锁定状态,可以选择超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入写入模式,则为true;否则为false。
///</returns>
///<paramname="timeout">等待的间隔;或为-1毫秒,表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="timeout"/>为负数,但它不等于-1毫秒为单位),这是唯一允许的值为负。-或-值<paramrefname="timeout"/>大于<seecref="F:System.Int32.MaxValue"/>毫秒为单位)。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterWriteLock(TimeSpantimeout);
///<summary>
///尝试进入写入模式锁定状态,可以选择超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入写入模式,则为true;否则为false。
///</returns>
///<paramname="millisecondsTimeout">等待的毫秒数,或为-1(<seecref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-当前线程最初在读取模式中,输入该锁,因此尝试进入写入模式会创建导致死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="millisecondsTimeout"/>为负数,但它不是等于<seecref="F:System.Threading.Timeout.Infinite"/>(-1),这是唯一允许的值为负。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterWriteLock(intmillisecondsTimeout);
///<summary>
///尝试进入可升级模式锁定状态。
///</summary>
///<exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已在任何模式下进入该锁。-或-当前线程已进入读取的模式,因此尝试进入可升级模式将有死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicvoidEnterUpgradeableReadLock();
///<summary>
///尝试进入可升级模式锁定状态,可以选择超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入可升级模式,则为true;否则为false。
///</returns>
///<paramname="timeout">等待的间隔;或为-1毫秒,表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="timeout"/>为负数,但它不等于-1毫秒为单位),这是唯一允许的值为负。-或-值<paramrefname="timeout"/>大于<seecref="F:System.Int32.MaxValue"/>毫秒为单位)。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterUpgradeableReadLock(TimeSpantimeout);
///<summary>
///尝试进入可升级模式锁定状态,可以选择超时时间。
///</summary>
///
///<returns>
///如果调用线程已进入可升级模式,则为true;否则为false。
///</returns>
///<paramname="millisecondsTimeout">等待的毫秒数,或为-1(<seecref="F:System.Threading.Timeout.Infinite"/>),表示无限期等待。</param><exceptioncref="T:System.Threading.LockRecursionException"><seecref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/>属性是<seecref="F:System.Threading.LockRecursionPolicy.NoRecursion"/>和当前的线程已进入该锁。-或-当前线程最初在读取模式中,输入该锁,因此尝试进入可升级模式会创建导致死锁的可能性。-或-递归数将超出该计数器的容量。限制为应用程序应永远不会遇到它太大。</exception><exceptioncref="T:System.ArgumentOutOfRangeException">值<paramrefname="millisecondsTimeout"/>为负数,但它不是等于<seecref="F:System.Threading.Timeout.Infinite"/>(-1),这是唯一允许的值为负。</exception><exceptioncref="T:System.ObjectDisposedException"><seecref="T:System.Threading.ReaderWriterLockSlim"/>对象已被释放。</exception>
[__DynamicallyInvokable]
publicboolTryEnterUpgradeableReadLock(intmillisecondsTimeout);
///<summary>
///减少读取模式的递归计数,并在生成的计数为0(零)时退出读取模式。
///</summary>
///<exceptioncref="T:System.Threading.SynchronizationLockException">在读取模式中,当前线程不已进入该锁。</exception>
[__DynamicallyInvokable]
publicvoidExitReadLock();
///<summary>
///减少写入模式的递归计数,并在生成的计数为0(零)时退出写入模式。
///</summary>
///<exceptioncref="T:System.Threading.SynchronizationLockException">当前线程不已进入写入模式的锁定。</exception>
[__DynamicallyInvokable]
publicvoidExitWriteLock();
///<summary>
///减少可升级模式的递归计数,并在生成的计数为0(零)时退出可升级模式。
///</summary>
///<exceptioncref="T:System.Threading.SynchronizationLockException">当前线程不已进入可升级模式的锁定。</exception>
[__DynamicallyInvokable]
publicvoidExitUpgradeableReadLock();
///<summary>
///释放<seecref="T:System.Threading.ReaderWriterLockSlim"/>类的当前实例所使用的所有资源。
///</summary>
///<exceptioncref="T:System.Threading.SynchronizationLockException"><seecref="P:System.Threading.ReaderWriterLockSlim.WaitingReadCount"/>是大于零。-或-<seecref="P:System.Threading.ReaderWriterLockSlim.WaitingUpgradeCount"/>是大于零。-或-<seecref="P:System.Threading.ReaderWriterLockSlim.WaitingWriteCount"/>是大于零。</exception><filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicvoidDispose();
///<summary>
///获取一个值,该值指示当前线程是否已进入读取模式的锁定状态。
///</summary>
///
///<returns>
///如果当前线程已进入读取模式,则为true;否则为false。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicboolIsReadLockHeld{[__DynamicallyInvokable]get;}
///<summary>
///获取一个值,该值指示当前线程是否已进入可升级模式的锁定状态。
///</summary>
///
///<returns>
///如果当前线程已进入可升级模式,则为true;否则为false。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicboolIsUpgradeableReadLockHeld{[__DynamicallyInvokable]get;}
///<summary>
///获取一个值,该值指示当前线程是否已进入写入模式的锁定状态。
///</summary>
///
///<returns>
///如果当前线程已进入写入模式,则为true;否则为false。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicboolIsWriteLockHeld{[__DynamicallyInvokable]get;}
///<summary>
///获取一个值,该值指示当前<seecref="T:System.Threading.ReaderWriterLockSlim"/>对象的递归策略。
///</summary>
///
///<returns>
///枚举值之一,用于指定锁定递归策略。
///</returns>
[__DynamicallyInvokable]
publicLockRecursionPolicyRecursionPolicy{[__DynamicallyInvokable]get;}
///<summary>
///获取已进入读取模式锁定状态的独有线程的总数。
///</summary>
///
///<returns>
///已进入读取模式锁定状态的独有线程的数量。
///</returns>
[__DynamicallyInvokable]
publicintCurrentReadCount{[__DynamicallyInvokable]get;}
///<summary>
///获取当前线程进入读取模式锁定状态的次数,用于指示递归。
///</summary>
///
///<returns>
///如果当前线程未进入读取模式,则为0(零);如果线程已进入读取模式但却不是以递归方式进入的,则为1;或者如果线程已经以递归方式进入锁定模式n-1次,则为n。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintRecursiveReadCount{[__DynamicallyInvokable]get;}
///<summary>
///获取当前线程进入可升级模式锁定状态的次数,用于指示递归。
///</summary>
///
///<returns>
///如果当前线程没有进入可升级模式,则为0;如果线程已进入可升级模式却不是以递归方式进入的,则为1;或者如果线程已经以递归方式进入可升级模式n-1次,则为n。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintRecursiveUpgradeCount{[__DynamicallyInvokable]get;}
///<summary>
///获取当前线程进入写入模式锁定状态的次数,用于指示递归。
///</summary>
///
///<returns>
///如果当前线程没有进入写入模式,则为0;如果线程已进入写入模式却不是以递归方式进入的,则为1;或者如果线程已经以递归方式进入写入模式n-1次,则为n。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintRecursiveWriteCount{[__DynamicallyInvokable]get;}
///<summary>
///获取等待进入读取模式锁定状态的线程总数。
///</summary>
///
///<returns>
///等待进入读取模式的线程总数。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintWaitingReadCount{[__DynamicallyInvokable]get;}
///<summary>
///获取等待进入可升级模式锁定状态的线程总数。
///</summary>
///
///<returns>
///等待进入可升级模式的线程总数。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintWaitingUpgradeCount{[__DynamicallyInvokable]get;}
///<summary>
///获取等待进入写入模式锁定状态的线程总数。
///</summary>
///
///<returns>
///等待进入写入模式的线程总数。
///</returns>
///<filterpriority>2</filterpriority>
[__DynamicallyInvokable]
publicintWaitingWriteCount{[__DynamicallyInvokable]get;}
}
以上是对Stack和线程的相关知识的浅述,现在介绍一下线程安全的Stack:
///<summary>
///表示对象的后进先出线程安全集合(栈结构)
///</summary>
///<typeparamname="T"></typeparam>
publicclassTStack<T>:IEnumerable<T>,ICollection
{
///<summary>
///内部堆栈
///</summary>
privatereadonlyStack<T>_mStack;
///<summary>
///锁访问堆栈(用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。)
///</summary>
privatereadonlyReaderWriterLockSlim_lockStack=newReaderWriterLockSlim();
///<summary>
///仅用于SyncRoot属性
///</summary>
privatereadonlyobject_objSyncRoot=newobject();
//Variables
///<summary>
///初始化一个新的实例<seecref="TStack{T}"/>class.
///</summary>
publicTStack()
{
_mStack=newStack<T>();
}
///<summary>
///初始化一个新的实例<seecref="TStack{T}"/>class.
///</summary>
///<paramname="col">
///开始集合
///</param>
publicTStack(IEnumerable<T>col)
{
_mStack=newStack<T>(col);
}
//Init
///<summary>
///获取枚举器
///</summary>
publicIEnumerator<T>GetEnumerator()
{
Stack<T>localStack=null;
//初始化枚举器
_lockStack.PerformUsingReadLock(()=>
{
//创建一个m_tlist副本
localStack=newStack<T>(_mStack);
});
//获取枚举器
foreach(TiteminlocalStack)
yieldreturnitem;
}
///<summary>
///获取枚举器
///</summary>
IEnumeratorIEnumerable.GetEnumerator()
{
Stack<T>localStack=null;
//初始化枚举器
_lockStack.PerformUsingReadLock(()=>
{
//创建一个m_TList的副本
localStack=newStack<T>(_mStack);
});
//获取枚举器
foreach(TiteminlocalStack)
yieldreturnitem;
}
///<summary>
///复制到一个数组
///</summary>
///<paramname="array"></param>
///<paramname="index"></param>
publicvoidCopyTo(Arrayarray,intindex)
{
_lockStack.PerformUsingReadLock(()=>_mStack.ToArray().CopyTo(array,index));
}
///<summary>
///堆栈中的项目数
///</summary>
publicintCount
{
get
{
return_lockStack.PerformUsingReadLock(()=>_mStack.Count);
}
}
///<summary>
///总为真
///</summary>
publicboolIsSynchronized
{
get{returntrue;}
}
///<summary>
///同步根
///</summary>
publicobjectSyncRoot
{
get{return_objSyncRoot;}
}
///<summary>
///清除集合
///</summary>
publicvoidClear()
{
_lockStack.PerformUsingWriteLock(()=>_mStack.Clear());
}
//Clear
///<summary>
///如果项目在堆栈中,则为true
///</summary>
///<paramname="item"></param>
///<returns></returns>
publicboolContains(Titem)
{
return_lockStack.PerformUsingReadLock(()=>_mStack.Contains(item));
}
//包含
///<summary>
///返回堆栈中的顶部项,而不从堆栈中删除它
///</summary>
///<returns></returns>
publicTPeek()
{
return_lockStack.PerformUsingReadLock(()=>_mStack.Peek());
}
//Peek
///<summary>
///删除并返回堆栈中的顶部项目
///</summary>
///<returns></returns>
publicTPop()
{
return_lockStack.PerformUsingWriteLock(()=>_mStack.Pop());
}
//Pop
///<summary>
///将一个项目插入堆栈
///</summary>
///<paramname="item"></param>
publicvoidPush(Titem)
{
_lockStack.PerformUsingWriteLock(()=>_mStack.Push(item));
}
//Push
///<summary>
///将堆栈转换为数组
///</summary>
///<returns></returns>
publicT[]ToArray()
{
return_lockStack.PerformUsingReadLock(()=>_mStack.ToArray());
}
//ToArray
///<summary>
///将容量设置为堆栈中实际的元素数量
///</summary>
publicvoidTrimExcess()
{
_lockStack.PerformUsingWriteLock(()=>_mStack.TrimExcess());
}
}
以上的操作方法继承了IEnumerable<T>,ICollection两个接口。有兴趣的,可以对IEnumerable<T>,ICollection两个接口进行细致的了解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。