C# ConcurrentStack实现
来源:互联网 发布:域名注册管理机构 编辑:程序博客网 时间:2024/06/11 20:39
我们通过C# Queue 和Stack的实现知道Stack是依靠数组实现的,那么ConcurrentStack的栈又是如何实现的了,然后它的线程安全又是怎么做到的了? 来看看其code吧
public class ConcurrentStack<T> : IProducerConsumerCollection<T>, IReadOnlyCollection<T> { private class Node { internal readonly T m_value; // Value of the node. internal Node m_next; // Next pointer. internal Node(T value) { m_value = value; m_next = null; } } private volatile Node m_head; private const int BACKOFF_MAX_YIELDS = 8; public ConcurrentStack(){} public ConcurrentStack(IEnumerable<T> collection) { if (collection == null) { throw new ArgumentNullException("collection"); } InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable<T> collection) { // We just copy the contents of the collection to our stack. Node lastNode = null; foreach (T element in collection) { Node newNode = new Node(element); newNode.m_next = lastNode; lastNode = newNode; } m_head = lastNode; } public void Push(T item) { Node newNode = new Node(item); newNode.m_next = m_head; if (Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next) { return; } PushCore(newNode, newNode); } private void PushCore(Node head, Node tail) { SpinWait spin = new SpinWait(); do { spin.SpinOnce(); // Reread the head and link our new node. tail.m_next = m_head; } while (Interlocked.CompareExchange(ref m_head, head, tail.m_next) != tail.m_next); } public bool TryPop(out T result) { Node head = m_head; //stack is empty if (head == null) { result = default(T); return false; } if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head) { result = head.m_value; return true; } return TryPopCore(out result); } private bool TryPopCore(out T result) { Node poppedNode; if (TryPopCore(1, out poppedNode) == 1) { result = poppedNode.m_value; return true; } result = default(T); return false; } private int TryPopCore(int count, out Node poppedHead) { SpinWait spin = new SpinWait(); Node head; Node next; int backoff = 1; Random r = new Random(Environment.TickCount & Int32.MaxValue); // avoid the case where TickCount could return Int32.MinValue while (true) { head = m_head; // Is the stack empty? if (head == null) { poppedHead = null; return 0; } next = head; int nodesCount = 1; for (; nodesCount < count && next.m_next != null; nodesCount++) { next = next.m_next; } // Try to swap the new head. If we succeed, break out of the loop. if (Interlocked.CompareExchange(ref m_head, next.m_next, head) == head) { poppedHead = head; return nodesCount; } // We failed to CAS the new head. Spin briefly and retry. for (int i = 0; i < backoff; i++) { spin.SpinOnce(); } backoff = spin.NextSpinWillYield ? r.Next(1, BACKOFF_MAX_YIELDS) : backoff * 2; } } }
ConcurrentStack<T>里面有一个内部类Node,看到这里我们就知道ConcurrentStack<T>的栈是一开节点Node来做的一个链表,非常好理解。那么线程安全又是怎么做到的了?首先我们来看看Push放法,首先我们需要新实例一个Node,并且新Node的m_next指向现有m_head头节点【newNode.m_next = m_head】,然后在原子比较newNode.m_next 是否是m_head【Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next】,如果是那么把m_head改为newNode ,push操作完成。如果第一个线程newNode.m_next = m_head之后,有新的线程执行了Interlocked.CompareExchange(ref m_head, newNode, newNode.m_next) == newNode.m_next 那么push就需要执行PushCore方法;该方法先自旋一下,然后在Interlocked.CompareExchange(ref m_head, head, tail.m_next) != tail.m_next【这里head和tail是新节点,tail.m_next是指向m_head】,如果当前线程是最新最近的那个 ,那么这个Interlocked.CompareExchange(ref m_head, head, tail.m_next) == tail.m_next就为true,退出循环,否者自旋后再次比较赋值。那么TryPop的实现也是类似的,如果if (Interlocked.CompareExchange(ref m_head, head.m_next, head) == head)成立那么直接返回,否者调用TryPopCore方法。而TryPopCore方法的核心是 if (Interlocked.CompareExchange(ref m_head, next.m_next, head) == head),如果成立则退出,否者自旋,至于自旋的次数来源于for (int i = 0; i < backoff; i++){ spin.SpinOnce(); }。是不是很简单了,但是也很巧妙啊。线程安全依靠SpinWait 的自旋和原子操作Interlocked.CompareExchange来实现的。
- C# ConcurrentStack实现
- 【C#】56. .Net中的并发集合——ConcurrentStack
- C#实现网段扫描
- C#实现WEB服务器
- C#实现Singleton
- C#实现网段扫描
- spider的 c#实现
- C# 实现网段扫描
- C#实现WEB服务器
- 用C#实现木马程序
- C#实现缩略图
- C#实现网段扫描
- C#实现网段扫描
- C#实现WEB服务器
- C#实现九九乘法表
- C#实现Singleton
- C#实现在线升级
- c#中实现缩略图
- chrome谷歌浏览器开启webgl
- 53.Maximum Subarray
- 使用mongodb的findAndModify命令来进行数据同步
- 【Scikit-Learn 中文文档】交叉分解
- PHP重置数组为连续数字索引的几种方式
- C# ConcurrentStack实现
- linux下生成core dump文件方法及设置 bug定位
- MyBatis初学
- Mat和IplImage访问像素的方法总结
- gpio学习
- 2017年11月12日所看链接(GSON 泛型 下载)
- iOS性能优化系列之__builtin_expect分支预测优化
- 如何扛住1.8亿/秒的双11数据洪峰?阿里流计算技术全揭秘
- 基础登录界面+第三方登录代码片