没错,这次章节没有女仆。 
 
 
 
前情回顾 
我们的最初的需求是建立一个拉模式下用户暂存的顺序信息池 
 
 
还是这张工作模式图 我们可以把这个需求设计为 
 
 
 
 
- 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,我们就可以把它放进这个池中了 
 

 Code
Code
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
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
    }
}
 
 
 
这里提供一个 MVC的测试聊天室  包括所有源代码
 
 
下载
 
大厅源代码正在googlecode 上用c#缓慢重建   有兴趣的可以下载
wgs-game-lobby.googlecode.com
 
 
 
连接:
游戏大厅 从基础开始(1)——最简单的关系,用户与房间 
游戏大厅 从基础开始(2)——最基础的交流:聊天 
游戏大厅 从基础开始(3)——最吸引眼球的部分 客户端与服务器的连接
游戏大厅 从基础开始(3.5)——最吸引眼球的部分 客户端与服务器的连接 的实现  
游戏大厅 从基础开始(4)-通过L2X用配置文件反射组装程序(VB only) 
游戏大厅 从基础开始(5)--绕回来细说聊天室(上) 
游戏大厅 从基础开始(6)--绕回来细说聊天室(中)之女仆编年史1
游戏大厅 从基础开始(7)--绕回来细说聊天室(中间偏下)之女仆编年史2 
游戏大厅 从基础开始(8)--绕回来细说聊天室(下)垃圾列表