ConcurrentQueue<T>队列是一个高效的线程安全的队列,是.Net Framework 4.0,System.Collections.Concurrent命名空间下的一个数据结构。

ConcurrentQueue<T>数据结构

下图是ConcurrentQueue<T>数据结构的示意图:

ConcurrentQueue<T>队列由若干Segment动态构成,每个Segment是一块连续的内存Buffer,大小固定为SEGMENT_SIZE。

ConcurrentQueue<T>私有成员变量

ConcurrentQueue<T>类有三个私有成员变量:

Segment* volatile m_head;

Segment* volatile m_tail;

Segment* volatile m_base;

m_head指向第一个segment,m_tail指向最后一个segment。这两个指针指向的对象,随着入队列和出队列操作而不断变化。

m_base指针固定指向ConcurrentQueue<T>实例化的第一个Segment,在析构ConcurrentQueue<T>对象时使用。

ConcurrentQueue<T>成员方法

void Enqueue(T item)
1
2
3
4
5
6
7
8
void Enqueue(T item)
{
    DNetSpinWait wait;
    while (!m_tail->TryAppend(item, &m_tail))
    {
        wait.SpinOnce();
    }
}
1
从m_tail指向的segment中,加入item的值,直到成功加入,函数返回。

该函数会在分配了新的segment后,更新m_tail指针。

bool TryDequeue(T* result)
1
2
3
4
5
6
7
8
9
10
11
12
13
bool TryDequeue(T* result)
{
 
    while (!IsEmpty())
    {
        if (m_head->TryRemove(result, &m_head))
        {
            return true;
        }  
    }
    result = NULL;
    return false;
}

如果当前队列为空,返回false,否则返回队列的第一个元素。

bool TryPeek(T* result)
1
2
3
4
5
6
7
8
9
10
11
12
bool TryPeek(T* result)
{
    while (!IsEmpty())
    {
        if (m_head->TryPeek(result))
        {
            return true;
        }
    }
    result = NULL;
    return false;
}

跟TryDequeue()方法相似。

int Count()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int Count()
{
    Segment* segment;
    Segment* segment2;
    int num;
    int num2;
    GetHeadTailPositions(&segment, &segment2, &num, &num2);
    if (segment == segment2)
    {
        return ((num2 - num) + 1);
    }
    int num3 = SEGMENT_SIZE - num;
    num3 += SEGMENT_SIZE * (((int) (segment2->GetIndex() - segment->GetIndex())) - 1);
    return (num3 + (num2 + 1));
}

通过得到当前首尾的segment指针,以及首指针的m_low索引,以及尾指针的m_high索引,计算当前队列中元素的个数。

该方法用到了GetHeadTailPositions方法。

bool IsEmpty()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool IsEmpty()
{
    Segment* head = m_head;
    if (head->IsEmpty())
    {
        if (head->GetNext() == NULL)
        {
            return true;
        }
        DNetSpinWait wait;
        while (head->IsEmpty())
        {
            if (head->GetNext() == NULL)
            {
                return true;
            }
            wait.SpinOnce();
            head = m_head;
        }
    }
    return false;
}

判定当前队列为空有两个条件,第一,m_head指向的segment为空;第二,m_head->GetNext()也为空,即m_head和m_tail指向同一个segment。

void Reset()
1
2
3
4
5
void Reset()
{
    DeleteNodes();
    m_base = m_head = m_tail = new Segment(0);
}

重置ConcurrentQueue<T>对象,删除已经分配了的segment,并重新更新成员变量的值。

void GetHeadTailPositions(Segment** head, Segment** tail, int* headLow, int* tailHigh)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void GetHeadTailPositions(Segment** head, Segment** tail, int* headLow, int* tailHigh)
{
    *head = m_head;
    *tail = m_tail;
    *headLow = (*head)->GetLow();
    *tailHigh = (*tail)->GetHigh();
    DNetSpinWait wait;
    while ((((*head != m_head) || (*tail != m_tail)) ||
        ((*headLow != (*head)->GetLow()) || (*tailHigh != (*tail)->GetHigh()))) ||
        ((*head)->GetIndex() > (*tail)->GetIndex()))
    {
        wait.SpinOnce();
        *head = m_head;
        *tail = m_tail;
        *headLow = (*head)->GetLow();
        *tailHigh = (*tail)->GetHigh();
    }
}

该函数就是将队列当前的m_head, m_tail指针以及m_head的m_low索引,m_tail的m_high索引取出来,放到线程栈上。并且在取出这些值后,再判断这些值是否合法。

c#高效的线程安全队列ConcurrentQueue<T>(上)的更多相关文章

  1. c# 高效的线程安全队列ConcurrentQueue

    c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...

  2. c# 高效的线程安全队列ConcurrentQueue(下) Segment类

    Segment成员变量 long long m_index; 记录该segment的索引号. int* volatile m_state; 状态数组,标识所对应的元素节点的状态,默认值为0,如果该元素 ...

  3. C#-----线程安全的ConcurrentQueue<T>队列

     ConcurrentQueue<T>队列是一个高效的线程安全的队列,是.Net Framework 4.0,System.Collections.Concurrent命名空间下的一个数据 ...

  4. 线程安全的ConcurrentQueue<T>队列

    队列(Queue)代表了一个先进先出的对象集合.当您需要对各项进行先进先出的访问时,则使用队列.当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队. ConcurrentQueue< ...

  5. [一起读源码]走进C#并发队列ConcurrentQueue的内部世界

    决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...

  6. 线程池 队列 synchronized

    线程池 BlockingQueue synchronized volatile 本章从线程池到阻塞队列BlockingQueue.从BlockingQueue到synchronized 和 volat ...

  7. 生产消费模式:多线程读写队列ConcurrentQueue

    需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子. 直接上代码,看下实现: // 初始化列队缓冲区 队列大小为100 IDataCollection<List&l ...

  8. C#数据结构-线程安全队列

    什么是线程安全? 答:线程安全是多线程编程时的计算机程序代码中的一个概念.在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意 ...

  9. Linux多线程系列-2-条件变量的使用(线程安全队列的实现)

    多线程情况下,往往需要使用互斥变量来实现线程间的同步,实现资源正确共享. linux下使用如下变量和函数 //条件变量 pthread_cond_t int pthread_cond_init (pt ...

随机推荐

  1. Java多线程学习总结--线程同步(2)

    线程同步是为了让多个线程在共享数据时,保持数据的一致性.举个例子,有两个人同时取钱,假设用户账户余额是1000,第一个用户取钱800,在第一个用户取钱的同时,第二个用户取钱600.银行规定,用户不允许 ...

  2. 【转】内网yum源搭建

    我们内网yum要玩的话,先加hosts,然后找运维要CentOS_base.repo这个文件,然后yum clean all   && yum makecache ========== ...

  3. phonegap 新窗口 WebView

    自定义WebView窗口打开 import com.ap.work.QuickWeb public class QuickPlugin extends CordovaPlugin { /** * 新开 ...

  4. ntpd和ntpdate

    以无GUI 的Ubuntu 为例 1. ntpdate ntpdate是Ubuntu发行版的标配.按Ubuntu14.04的官方文档(这里),Ubuntu在启动时,会调用ntpdate,根据Ubunt ...

  5. ICON的设计很重要

    ICON的设计很重要 发布者: wuye | 发布时间: 2014-12-19 17:45| 评论数: 0 游戏类型:手游游戏/平板游戏  设计类型:[功能/模块/UI] 作者:小金狮的UI分享 每个 ...

  6. Unix 环境高级编程---线程创建、同步、

    一下代码主要实现了linux下线程创建的基本方法,这些都是使用默认属性的.以后有机会再探讨自定义属性的情况.主要是为了练习三种基本的线程同步方法:互斥.读写锁以及条件变量. #include < ...

  7. HDU 5858 Hard problem (数学推导)

    Hard problem 题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=5858 Description cjj is fun with ...

  8. hdu 2084 数塔 (简单dp)

    http://acm.hdu.edu.cn/showproblem.php?pid=2084 数塔 Time Limit: 1000/1000 MS (Java/Others)    Memory L ...

  9. VS2008注册码

    PYHYP-WXB3B-B2CCM-V9DX9-VDY8T 如果下载的是90天的试用版,下载下来以后把ISO里面的Setup\setup.sdb文件用记事本打开,把其中的[Product Key]下面 ...

  10. c#学习之旅------01

    一.交换两个数的值 //交换两个数的值 #region 方法一 , num2 = ;//待交换的两个数值 int temp;//临时变量 temp = num1; num1 = num2; num2 ...