前情回顧 我們的最初的需求是建立一個拉模式下用戶暫存的順序信息池
還是這張工作模式圖 我們可以把這個需求設計為
Clear:清除所有內容
GetEnumerator :實現枚舉器,新向舊方向的順序枚舉,這樣一旦到達上次讀取的時間就可以中斷 枚舉。
RecycleFromButtom:從舊向前進行搜索 把滿足條件的扔到GC
StackOn :把一個新 信息放在堆棧的頂部
這就好像是一個舊報紙回收傳送帶,一群人在焚燒之前看看還有沒有什麼值 得保存的信息 排個照,存個檔,沒有用的就直接扔進焚化爐。
實現設計
根據上一章的研 究結果 我們需要一個能夠在寫的同時 能夠完全無鎖並發訪問的順序數據池
看起來基於 Array的 任何數據結構都不太適合並發讀。
這時候我們把目光轉向鏈表結構。
鏈表在實現聊天室時 得天獨厚
姑且我們為垃圾列表建立這樣一個鏈表節點
public void StackOn( IRecycleNode<T> newOne)
{
_lock.EnterWriteLock ();
newOne.Lower = newOne.Higher = null;
if (_Top != null)
{
_Top.Higher = newOne;
newOne.Lower = _Top;
_Top = newOne;
}
else
{
_Top =newOne ;
_Bottom = _Top;
}
newOne.TimeStamp = DateTime.Now;
_lock.ExitWriteLock();
}
我們以此作 為基礎繼續討論。
關於枚舉器並發訪問
相比循環隊列中我們MoveNext的時候需要的 _size, _head, _index 和array中元素 這幾個變量隨時可能產生的並發沖突
public bool MoveNext()
{
if (this._version != this._q._version)
{
ThrowHelper.ThrowInvalidOperationException (ExceptionResource.InvalidOperation_EnumFailedVersion);
}
if (this._index == -2)
{
return false;
}
this._index++;
if (this._index == this._q._size)
{
this._index = -2;
this._currentElement = default(T);
return false;
}
this._currentElement = this._q.GetElement(this._index);
return true;
}
Queue:
internal T GetElement(int i)
{
return this._array[(this._head + i) % this._array.Length];
}
在MoveNext的時候 我們的RecycleList訪問的是一個不會髒的引用 : Lower
public bool MoveNext()
{
if (!startedFlag)
{
startedFlag =true ;
return (_beginNode != null);
};
var cl = _currentNode.Lower;
if (cl != null)
{
_currentNode = cl;
return true;
}
else
return false;
}
不沖突 就是不沖突~
關於並發回收
鏈表回收相當的簡單, node. Lower=null;
一旦node的lower設置為 null 那麼下面的所有節點就脫離了GCRoot 就可以被回收了
如果別的線程正在其下的_Bottom檢查回收, 由於 Higher的聯系仍然沒斷,向上的枚舉仍然可以進行
public void RecycleFromButtom(Func<IRecycleNode<T>, bool> RecycleCondition)
{
var bn = _Bottom;
//if (_Bottom == null) _Bottom = ;
var bh = bn;
if (bh != null) bh = bh.Higher;
while (bn != null & bh != null)
{
if (RecycleCondition(bn))
{
bh.Lower = null;
}
_Bottom = bh;
bn = _Bottom;
bh = bn.Higher;
}
}
_Bottom 決定了GC能夠回收的最後一個節點。 它不需要安全。 就算它被指定為 實際底部下 面的其他節點 也僅僅使一兩個節點苟延殘喘一個周期。
唯一的迷你鎖:StackOn
理論上 的完全無鎖 被破壞在寫入這一關。
由於在鏈表頭部增加節點並不是原子操作,所以這裡必須增 加一個寫入鎖
這個鎖非常非常的小 :
public void StackOn( IRecycleNode<T> newOne)
{
_lock.EnterWriteLock ();
newOne.Lower = newOne.Higher = null;
if (_Top != null)
{
_Top.Higher = newOne;
newOne.Lower = _Top;
_Top = newOne;
}
else
{
_Top =newOne ;
_Bottom = _Top;
}
newOne.TimeStamp = DateTime.Now;
_lock.ExitWriteLock();
}
由於 對_top的修改是原子性的
_Top.Higher = newOne;
newOne.Lower = _Top;
_Top = newOne;
在創建Enumertor的時候 完全可以髒讀 ————沒有人在意自己讀取的是最上面一條信息 還是第二個信息 他們只關心 是否能讀下去
只要我們的ChatMessage 實現 IRecycleNode,我們就可以把它放進這個池中了
namespace WayneGameSolution.Chat
{
public class ChatMessage : IChatMessage, IRecycleNode<IChatMessage>
{
public ChatMessage()
{ }
#region IChatMessage Members
public string ChannelID
{
get;
set;
}
public string ChannelName
{
get;
set;
}
public string ChaterFrom
{
get;
set;
}
public string ChaterTo
{
get;
set;
}
public MessageRenderType RenderType
{
get;
set;
}
public string Text
{
get;
set;
}
public DateTime TimeStamp
{
get;
set;
}
#endregion
#region ICloneable Members
public object Clone()
{
return MemberwiseClone();
}
#endregion
#region IRecycleNode<IChatMessage> Members
public IRecycleNode<IChatMessage> Lower
{
get;
set;
}
public IRecycleNode<IChatMessage> Higher
{
get;
set;
}
public IChatMessage Value
{
get
{
return this;
}
set
{
throw new NotImplementedException();
}
}
#endregion
}
}
垃圾列表最終定稿
RecycleList
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Security.Permissions;
namespace System.Collections.Generic.Sync
{
public class RecycleList<T> : IEnumerable<T>
{
System.Threading.ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
IRecycleNode<T> _Bottom, _Top;
//public IRecycleNode<T> Top
//{
// get
// {
// _lock.EnterReadLock ();
// var t = _Top;
// _lock.ExitReadLock();
// return t;
// }
//}
public void Clear()
{
_lock.EnterWriteLock();
_Top = null;
_lock.ExitWriteLock();
}
public void StackOn( IRecycleNode<T> newOne)
{
_lock.EnterWriteLock ();
newOne.Lower = newOne.Higher = null;
if (_Top != null)
{
_Top.Higher = newOne;
newOne.Lower = _Top;
_Top = newOne;
}
else
{
_Top =newOne ;
_Bottom = _Top;
}
newOne.TimeStamp = DateTime.Now;
_lock.ExitWriteLock();
}
public void RecycleFromButtom (Func<IRecycleNode<T>, bool> RecycleCondition)
{
var bn = _Bottom;
//if (_Bottom == null) _Bottom = ;
var bh = bn;
if (bh != null) bh = bh.Higher;
while (bn != null & bh != null)
{
if (RecycleCondition(bn))
{
bh.Lower = null;
}
_Bottom = bh;
bn = _Bottom;
bh = bn.Higher;
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return new RecycleListEnumerator<T>(_Top);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return new RecycleListEnumerator<T>(_Top);
}
#endregion
}
public interface IRecycleNode<T>
{
IRecycleNode<T> Lower { get; set; }
IRecycleNode<T> Higher { get; set; }
T Value { get; set; }
DateTime TimeStamp
{
get;
set;
}
}
public class RecycleListEnumerator<T> : IEnumerator<T>
{
IRecycleNode<T> _beginNode;
IRecycleNode<T> _currentNode;
public RecycleListEnumerator(IRecycleNode<T> beginNode)
{
_beginNode = _currentNode = beginNode;
}
#region IEnumerator<T> Members
public T Current
{
get { return _currentNode.Value; }
}
#endregion
#region IDisposable Members
public void Dispose()
{
_beginNode = null;
_currentNode = null;
}
#endregion
#region IEnumerator Members
object IEnumerator.Current
{
get { return Current; }
}
private bool startedFlag=false ;
public bool MoveNext()
{
if (!startedFlag)
{
startedFlag =true ;
return (_beginNode != null);
};
var cl = _currentNode.Lower;
if (cl != null)
{
_currentNode = cl;
return true;
}
else
return false;
}
public void Reset()
{
_currentNode = _beginNode;
}
#endregion
}
}