在C#中,用於儲存的結構較多,如:DataTable,DataSet,List,Dictionary,Stack等結構,各種結構採用的儲存的方式存在差異,效率也必然各有優缺點。現在介紹一種後進先出的資料結構。
談到儲存結構,我們在項目中使用的較多。對於Task儲存結構,棧與隊列是類似的結構,在使用的時候採用不同的方法。C#中棧(Stack)是編譯期間就分配好的記憶體空間,因此你的代碼中必須就棧的大小有明確的定義;堆是程式運行期間動態分配的記憶體空間,你可以根據程式的運行情況確定要分配的堆記憶體的大小。
在C#中,棧通常儲存著我們代碼執行的步驟。C#中的參考型別儲存在棧中,在程式啟動並執行時候,每個線程(Thread)都會維護一個自己的專屬線程堆棧。當一個方法被調用的時候,主線程開始在所屬程式集的中繼資料中,尋找被呼叫者法,然後通過JIT即時編譯並把結果(一般是本地CPU指令)放在棧頂。CPU通過匯流排從棧頂取指令,驅動程式以執行下去。
以上對棧這個資料結構進行了一個簡單的介紹,現在看一下C#實現棧結構的底層方法:
/// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 類的新執行個體,該執行個體為空白並且具有預設初始容量。 /// </summary> [__DynamicallyInvokable] public Stack(); /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 類的新執行個體,該執行個體為空白,具有指定的初始容量或預設的初始容量(其中較大的一個)。 /// </summary> /// <param name="capacity"><see cref="T:System.Collections.Generic.Stack`1"/> 可包含的初始元素數。</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than zero.</exception> [__DynamicallyInvokable] public Stack(int capacity); /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.Stack`1"/> 類的新執行個體,該執行個體包含從指定集合複製的元素並且具有足夠的容量來容納所複製的元素。 /// </summary> /// <param name="collection">從中複製元素的集合。</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception> [__DynamicallyInvokable] public Stack(IEnumerable<T> collection);
以上是對stack的部分方法的介紹,由於在操作資料儲存的同時,會考慮到線程的安全性。
進程作為作業系統執行程式的基本單位,擁有應用程式的資源,進程包含線程,進程的資源被線程共用,線程不擁有資源。線程分為前台線程和後台線程,通過Thread類建立線程預設為前台線程。當所有前台線程關閉時,所有的後台線程也會被直接終止,不會拋出異常。
接下來看一下ReaderWriterLockSlim類:
/// <summary> /// 表示用於管理資源訪問的鎖定狀態,可實現多線程讀取或進行獨佔式寫入訪問。 /// </summary> [__DynamicallyInvokable] [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)] public class ReaderWriterLockSlim : IDisposable { /// <summary> /// 使用預設屬性值初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 類的新執行個體。 /// </summary> [__DynamicallyInvokable] public ReaderWriterLockSlim(); /// <summary> /// 在指定鎖定遞迴策略的情況下初始化 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 類的新執行個體。 /// </summary> /// <param name="recursionPolicy">枚舉值之一,用於指定鎖定遞迴策略。</param> [__DynamicallyInvokable] public ReaderWriterLockSlim(LockRecursionPolicy recursionPolicy); /// <summary> /// 嘗試進入讀模數式鎖定狀態。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入讀取的模式。- 或 -當它已經包含寫入鎖時,當前線程可能不會擷取讀的鎖定。- 或 -遞迴數將超出該計數器的容量。此限制是很大的應用程式應永遠不會遇到它。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public void EnterReadLock(); /// <summary> /// 嘗試進入讀模數式鎖定狀態,可以選擇逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入讀模數式,則為 true;否則為 false。 /// </returns> /// <param name="timeout">等待的間隔;或為 -1 毫秒,表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 為負數,但它不等於-1 毫秒為單位),這是唯一允許的值為負。- 或 -值 <paramref name="timeout"/> 大於 <see cref="F:System.Int32.MaxValue"/> 毫秒為單位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterReadLock(TimeSpan timeout); /// <summary> /// 嘗試進入讀模數式鎖定狀態,可以選擇整數逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入讀模數式,則為 true;否則為 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒數,或為 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 為負數,但它不是等於 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),這是唯一允許的值為負。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterReadLock(int millisecondsTimeout); /// <summary> /// 嘗試進入寫入模式鎖定狀態。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已在任何模式下進入該鎖。- 或 -當前線程已進入讀取的模式,因此嘗試進入鎖定狀態寫入模式,則會建立導致死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public void EnterWriteLock(); /// <summary> /// 嘗試進入寫入模式鎖定狀態,可以選擇逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入寫入模式,則為 true;否則為 false。 /// </returns> /// <param name="timeout">等待的間隔;或為 -1 毫秒,表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -當前線程最初在讀模數式中,輸入該鎖,因此嘗試進入寫入模式會建立導致死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 為負數,但它不等於-1 毫秒為單位),這是唯一允許的值為負。- 或 -值 <paramref name="timeout"/> 大於 <see cref="F:System.Int32.MaxValue"/> 毫秒為單位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterWriteLock(TimeSpan timeout); /// <summary> /// 嘗試進入寫入模式鎖定狀態,可以選擇逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入寫入模式,則為 true;否則為 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒數,或為 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -當前線程最初在讀模數式中,輸入該鎖,因此嘗試進入寫入模式會建立導致死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 為負數,但它不是等於 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),這是唯一允許的值為負。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterWriteLock(int millisecondsTimeout); /// <summary> /// 嘗試進入可升級模式鎖定狀態。 /// </summary> /// <exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已在任何模式下進入該鎖。- 或 -當前線程已進入讀取的模式,因此嘗試進入可升級模式將有死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public void EnterUpgradeableReadLock(); /// <summary> /// 嘗試進入可升級模式鎖定狀態,可以選擇逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入可升級模式,則為 true;否則為 false。 /// </returns> /// <param name="timeout">等待的間隔;或為 -1 毫秒,表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -當前線程最初在讀模數式中,輸入該鎖,因此嘗試進入可升級模式會建立導致死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="timeout"/> 為負數,但它不等於-1 毫秒為單位),這是唯一允許的值為負。- 或 -值 <paramref name="timeout"/> 大於 <see cref="F:System.Int32.MaxValue"/> 毫秒為單位)。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterUpgradeableReadLock(TimeSpan timeout); /// <summary> /// 嘗試進入可升級模式鎖定狀態,可以選擇逾時時間。 /// </summary> /// /// <returns> /// 如果調用線程已進入可升級模式,則為 true;否則為 false。 /// </returns> /// <param name="millisecondsTimeout">等待的毫秒數,或為 -1 (<see cref="F:System.Threading.Timeout.Infinite"/>),表示無限期等待。</param><exception cref="T:System.Threading.LockRecursionException"><see cref="P:System.Threading.ReaderWriterLockSlim.RecursionPolicy"/> 屬性是 <see cref="F:System.Threading.LockRecursionPolicy.NoRecursion"/> 和當前的線程已進入該鎖。- 或 -當前線程最初在讀模數式中,輸入該鎖,因此嘗試進入可升級模式會建立導致死結的可能性。- 或 -遞迴數將超出該計數器的容量。限制為應用程式應永遠不會遇到它太大。</exception><exception cref="T:System.ArgumentOutOfRangeException">值 <paramref name="millisecondsTimeout"/> 為負數,但它不是等於 <see cref="F:System.Threading.Timeout.Infinite"/> (-1),這是唯一允許的值為負。</exception><exception cref="T:System.ObjectDisposedException"><see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象已被釋放。</exception> [__DynamicallyInvokable] public bool TryEnterUpgradeableReadLock(int millisecondsTimeout); /// <summary> /// 減少讀模數式的遞迴計數,並在產生的計數為 0(零)時退出讀模數式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">在讀模數式中,當前線程不已進入該鎖。</exception> [__DynamicallyInvokable] public void ExitReadLock(); /// <summary> /// 減少寫入模式的遞迴計數,並在產生的計數為 0(零)時退出寫入模式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">當前線程不已進入寫入模式的鎖定。</exception> [__DynamicallyInvokable] public void ExitWriteLock(); /// <summary> /// 減少可升級模式的遞迴計數,並在產生的計數為 0(零)時退出可升級模式。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException">當前線程不已進入可升級模式的鎖定。</exception> [__DynamicallyInvokable] public void ExitUpgradeableReadLock(); /// <summary> /// 釋放 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 類的當前執行個體所使用的所有資源。 /// </summary> /// <exception cref="T:System.Threading.SynchronizationLockException"><see cref="P:System.Threading.ReaderWriterLockSlim.WaitingReadCount"/> 是大於零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingUpgradeCount"/> 是大於零。- 或 -<see cref="P:System.Threading.ReaderWriterLockSlim.WaitingWriteCount"/> 是大於零。</exception><filterpriority>2</filterpriority> [__DynamicallyInvokable] public void Dispose(); /// <summary> /// 擷取一個值,該值指示當前線程是否已進入讀模數式的鎖定狀態。 /// </summary> /// /// <returns> /// 如果當前線程已進入讀模數式,則為 true;否則為 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsReadLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 擷取一個值,該值指示當前線程是否已進入可升級模式的鎖定狀態。 /// </summary> /// /// <returns> /// 如果當前線程已進入可升級模式,則為 true;否則為 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsUpgradeableReadLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 擷取一個值,該值指示當前線程是否已進入寫入模式的鎖定狀態。 /// </summary> /// /// <returns> /// 如果當前線程已進入寫入模式,則為 true;否則為 false。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public bool IsWriteLockHeld { [__DynamicallyInvokable] get; } /// <summary> /// 擷取一個值,該值指示當前 <see cref="T:System.Threading.ReaderWriterLockSlim"/> 對象的遞迴策略。 /// </summary> /// /// <returns> /// 枚舉值之一,用於指定鎖定遞迴策略。 /// </returns> [__DynamicallyInvokable] public LockRecursionPolicy RecursionPolicy { [__DynamicallyInvokable] get; } /// <summary> /// 擷取已進入讀模數式鎖定狀態的專屬線程的總數。 /// </summary> /// /// <returns> /// 已進入讀模數式鎖定狀態的專屬線程的數量。 /// </returns> [__DynamicallyInvokable] public int CurrentReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取當前線程進入讀模數式鎖定狀態的次數,用於指示遞迴。 /// </summary> /// /// <returns> /// 如果當前線程未進入讀模數式,則為 0(零);如果線程已進入讀模數式但卻不是以遞迴方式進入的,則為 1;或者如果線程已經以遞迴方式進入鎖定模式 n - 1 次,則為 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取當前線程進入可升級模式鎖定狀態的次數,用於指示遞迴。 /// </summary> /// /// <returns> /// 如果當前線程沒有進入可升級模式,則為 0;如果線程已進入可升級模式卻不是以遞迴方式進入的,則為 1;或者如果線程已經以遞迴方式進入可升級模式 n - 1 次,則為 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveUpgradeCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取當前線程進入寫入模式鎖定狀態的次數,用於指示遞迴。 /// </summary> /// /// <returns> /// 如果當前線程沒有進入寫入模式,則為 0;如果線程已進入寫入模式卻不是以遞迴方式進入的,則為 1;或者如果線程已經以遞迴方式進入寫入模式 n - 1 次,則為 n。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int RecursiveWriteCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取等待進入讀模數式鎖定狀態的線程總數。 /// </summary> /// /// <returns> /// 等待進入讀模數式的線程總數。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingReadCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取等待進入可升級模式鎖定狀態的線程總數。 /// </summary> /// /// <returns> /// 等待進入可升級模式的線程總數。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingUpgradeCount { [__DynamicallyInvokable] get; } /// <summary> /// 擷取等待進入寫入模式鎖定狀態的線程總數。 /// </summary> /// /// <returns> /// 等待進入寫入模式的線程總數。 /// </returns> /// <filterpriority>2</filterpriority> [__DynamicallyInvokable] public int WaitingWriteCount { [__DynamicallyInvokable] get; } }
以上是對Stack和線程的相關知識的淺述,現在介紹一下安全執行緒的Stack:
/// <summary> /// 表示對象的後進先出安全執行緒集合(棧結構) /// </summary> /// <typeparam name="T"></typeparam> public class TStack<T> : IEnumerable<T>, ICollection { /// <summary> /// 內部堆棧 /// </summary> private readonly Stack<T> _mStack; /// <summary> /// 鎖訪問堆棧(用於管理資源訪問的鎖定狀態,可實現多線程讀取或進行獨佔式寫入訪問。) /// </summary> private readonly ReaderWriterLockSlim _lockStack = new ReaderWriterLockSlim(); /// <summary> /// 僅用於SyncRoot屬性 /// </summary> private readonly object _objSyncRoot = new object(); // Variables /// <summary> /// 初始化一個新的執行個體 <see cref="TStack{T}"/> class. /// </summary> public TStack() { _mStack = new Stack<T>(); } /// <summary> /// 初始化一個新的執行個體 <see cref="TStack{T}"/> class. /// </summary> /// <param name="col"> /// 開始集合 /// </param> public TStack(IEnumerable<T> col) { _mStack = new Stack<T>(col); } // Init /// <summary> /// 擷取列舉程式 /// </summary> public IEnumerator<T> GetEnumerator() { Stack<T> localStack = null; // 初始化列舉程式 _lockStack.PerformUsingReadLock(() => { // 建立一個m_tlist副本 localStack = new Stack<T>(_mStack); }); // 擷取列舉程式 foreach (T item in localStack) yield return item; } /// <summary> /// 擷取列舉程式 /// </summary> IEnumerator IEnumerable.GetEnumerator() { Stack<T> localStack = null; // 初始化列舉程式 _lockStack.PerformUsingReadLock(() => { // 建立一個m_TList的副本 localStack = new Stack<T>(_mStack); }); // 擷取列舉程式 foreach (T item in localStack) yield return item; } /// <summary> /// 複製到一個數組 /// </summary> /// <param name="array"></param> /// <param name="index"></param> public void CopyTo(Array array, int index) { _lockStack.PerformUsingReadLock(() => _mStack.ToArray().CopyTo(array, index)); } /// <summary> ///堆棧中的項目數 /// </summary> public int Count { get { return _lockStack.PerformUsingReadLock(() => _mStack.Count); } } /// <summary> /// 總為真 /// </summary> public bool IsSynchronized { get { return true; } } /// <summary> ///同步根 /// </summary> public object SyncRoot { get { return _objSyncRoot; } } /// <summary> ///清除集合 /// </summary> public void Clear() { _lockStack.PerformUsingWriteLock(() => _mStack.Clear()); } // Clear /// <summary> ///如果項目在堆棧中,則為true /// </summary> /// <param name="item"></param> /// <returns></returns> public bool Contains(T item) { return _lockStack.PerformUsingReadLock(() => _mStack.Contains(item)); } // 包含 /// <summary> /// 返回堆棧中的頂部項,而不從堆棧中刪除它 /// </summary> /// <returns></returns> public T Peek() { return _lockStack.PerformUsingReadLock(() => _mStack.Peek()); } // Peek /// <summary> ///刪除並返回堆棧中的頂部項目 /// </summary> /// <returns></returns> public T Pop() { return _lockStack.PerformUsingWriteLock(() => _mStack.Pop()); } // Pop /// <summary> /// 將一個項目插入堆棧 /// </summary> /// <param name="item"></param> public void Push(T item) { _lockStack.PerformUsingWriteLock(() => _mStack.Push(item)); } // Push /// <summary> ///將堆棧轉換為數組 /// </summary> /// <returns></returns> public T[] ToArray() { return _lockStack.PerformUsingReadLock(() => _mStack.ToArray()); } // ToArray /// <summary> /// 將容量設定為堆棧中實際的元素數量 /// </summary> public void TrimExcess() { _lockStack.PerformUsingWriteLock(() => _mStack.TrimExcess()); } }
以上的操作方法繼承了IEnumerable<T>, ICollection兩個介面。有興趣的,可以對IEnumerable<T>, ICollection兩個介面進行細緻的瞭解。
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。