ConcurrentBag根据操作线程,对不同线程分配不同的队列进行数据操作。这样,每个队列只有一个线程在操作,不会发生并发问题。其内部实现运用了net4.0新加入的ThreadLocal线程本地存储功能。各个队列间通过链表维护。

其内部结构如下:

1、获取线程本地队列:

 /// <summary>
/// 获取当前线程的队列
/// </summary>
/// <param name="forceCreate">如果线程没有持有队列,是否新建</param>
/// <returns></returns>
private ThreadLocalList<T> GetThreadList(bool forceCreate)
{
//尝试获取线程本地队列列表(参考ThreadLocal),此处的m_locals不同线程持有不同实例
//如果获取为空,则说明线程是第一次执行此函数,需要分配一个队列
ThreadLocalList<T> unownedList = this.m_locals.Value;
if (unownedList != null)
{
return unownedList;
}
if (forceCreate)
{
//获取当前本地队列锁,防止在冻结队列时产生冲突(参考FreezeBag函数)
object globalListsLock = this.GlobalListsLock;
lock (globalListsLock)
{
//获取本地队列
//如果没有创建过队列,则创建一个新的队列;否则尽量分配已有的线程终止的队列
if (this.m_headList == null)
{
unownedList = new ThreadLocalList<T>(Thread.CurrentThread);
this.m_headList = unownedList;
this.m_tailList = unownedList;
}
else
{
//获取无主队列,不分配新队列
unownedList = this.GetUnownedList();
if (unownedList == null)
{
unownedList = new ThreadLocalList<T>(Thread.CurrentThread);
this.m_tailList.m_nextList = unownedList;
this.m_tailList = unownedList;
}
}
this.m_locals.Value = unownedList;
return unownedList;
}
}
return null;
}

获取当前线程持有的队列

2、获取无主队列

 /// <summary>
/// 获取无主队列
/// 如果当前队列的持有线程已经终止,则为无主队列
/// </summary>
/// <returns></returns>
private ThreadLocalList<T> GetUnownedList()
{
for (ThreadLocalList<T> list = this.m_headList; list != null; list = list.m_nextList)
{
if (list.m_ownerThread.ThreadState == System.Threading.ThreadState.Stopped)
{
list.m_ownerThread = Thread.CurrentThread;
return list;
}
}
return null;
}

获取无主队列

3、插入操作代码分析

 /// <summary>
/// 向Bag添加元素
/// </summary>
/// <param name="item"></param> [__DynamicallyInvokable]
public void Add(T item)
{
//获取当前线程持有的队列
ThreadLocalList<T> threadList = this.GetThreadList(true);
//向当前持有队列添加数据
this.AddInternal(threadList, item);
} /// <summary>
/// 向队列添加数据
/// </summary>
/// <param name="list"></param>
/// <param name="item"></param>
private void AddInternal(ThreadLocalList<T> list, T item)
{
bool lockTaken = false;
try
{
//CAS原子操作,设置标志位,与Steal和Freeze实现互斥
Interlocked.Exchange(ref list.m_currentOp, );
//如果m_needSync,则说明已经发起冻结操作,需要加锁保证线程安全
if ((list.Count < ) || this.m_needSync)
{
list.m_currentOp = ;
Monitor.Enter(list, ref lockTaken);
}
list.Add(item, lockTaken);
}
finally
{
list.m_currentOp = ;
if (lockTaken)
{
Monitor.Exit(list);
}
}
}

插入操作

4、冻结Bag函数

 /// <summary>
/// 冻结Bag,不能进行增,删,获取操作
/// </summary>
/// <param name="lockTaken"></param>
private void FreezeBag(ref bool lockTaken)
{
//获取当前线程list锁
Monitor.Enter(this.GlobalListsLock, ref lockTaken);
//设置同步标志位,增,删,获取操作识别此标志位,只有获取锁才能执行
this.m_needSync = true;
//获取所有list的锁
this.AcquireAllLocks();
//等待所有操作执行完成
this.WaitAllOperations();
}

冻结bag

5、转化成数组

 /// <summary>
/// 转化为数组
/// </summary>
/// <returns></returns>
[__DynamicallyInvokable]
public T[] ToArray()
{
T[] localArray;
//没有数据返回空数组
if (this.m_headList == null)
{
return new T[];
}
bool lockTaken = false;
try
{
//冻结bag
this.FreezeBag(ref lockTaken);
//转化成List后直接转成Array
localArray = this.ToList().ToArray();
}
finally
{
this.UnfreezeBag(lockTaken);
}
return localArray;
} /// <summary>
/// 转化成list
/// </summary>
/// <returns></returns>
private List<T> ToList()
{
List<T> list = new List<T>();
//获取所有list,遍历生成副本
for (ThreadLocalList<T> list2 = this.m_headList; list2 != null; list2 = list2.m_nextList)
{
for (Node<T> node = list2.m_head; node != null; node = node.m_next)
{
list.Add(node.m_value);
}
}
return list;
}

转化成数组

[.net]ConcurrentBag源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. SpringBoot2.0实现静态资源版本控制

    写在最前面 犹记毕业第一年时,公司每次发布完成后,都会在一个群里通知[版本更新,各部门清理缓存,有问题及时反馈]之类的话.归根结底就是资源缓存的问题,浏览器会将请求到的静态资源,如JS.CSS等文件缓 ...

  2. hadoop学习day2开发笔记

    1.将hdfs客户端开发所需的jar导入工程(jar包可在hadoop安装包中找到common/hdfs) 2.写代码 要对hdfs中的文件进行操作,代码中首先需要获得一个hdfs的客户端对象 Con ...

  3. firemonkey Grid自定义

    http://stackoverflow.com/questions/28893564/memory-leak-on-tstringgrids-ondrawcolumncell-event http: ...

  4. python 发送带附件的 邮件

    from email.MIMETextimportMIMETextfrom email.MIMEMultipartimportMIMEMultipartimport smtplib mail_host ...

  5. Apache ZooKeeper 单机、集群部署文档

    简介: Apache ZooKeeper 是一个分布式应用的高性能协调服务,功能包括:配置维护.统一命名.状态同步.集群管理.仲裁选举等. 下载地址:http://apache.fayea.com/z ...

  6. Python pip配置国内源

    众所周知,Python使用pip方法安装第三方包时,需要从 https://pypi.org/ 资源库中下载,但是会面临下载速度慢,甚至无法下载的尴尬,这时,你就需要知道配置一个国内源有多么重要了,通 ...

  7. 前端开发之jQuery篇--选择器

    主要内容: 1.jQuery简介 2.jQuery文件的引入 3.jQuery选择器 4.jQuery对象与DOM对象的转换 一.jQuery简介 1.介绍 jQuery是一个JavaScript库: ...

  8. fast-dfs

    转http://www.cnblogs.com/jym-sunshine/p/6397470.html FastDFS安装全过程记录 1.安装准备 HA虚拟IP:192.168.1.208 HA软件: ...

  9. MongoDB C# 驱动教程

    C# 驱动版本 v1.6.x 本教程基于C#驱动 v1.6.x . Api 文档见此处: http://api.mongodb.org/csharp/current/. 简介 本教程介绍由10gen支 ...

  10. asp.net安装指令

    cd \ cd C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319aspnet_regiis.exe -i注册.NET4到IIS