ConcurrentQueue<T>高效的线程安全的队列

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

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

ConcurrentQueue私有成员变量

ConcurrentQueue类有三个私有成员变量:

Segment* volatile m_head;

Segment* volatile m_tail;

Segment* volatile m_base;

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

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

ConcurrentQueue成员方法

void Enqueue(T item)



void Enqueue(T item)
{
    DNetSpinWait wait;
    while (!m_tail->TryAppend(item, &m_tail))
    {
        wait.SpinOnce();
    }
}

从m_tail指向的segment中,加入item的值,直到成功加入,函数返回。
该函数会在分配了新的segment后,更新m_tail指针。

bool TryDequeue(T* result)


bool TryDequeue(T* result)
{

    while (!IsEmpty())
    {
        if (m_head->TryRemove(result, &m_head))
        {
            return true;
        }   
    }
    result = NULL;
    return false;
}

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

bool TryPeek(T* result)

bool TryPeek(T* result)
{
    while (!IsEmpty())
    {
        if (m_head->TryPeek(result))
        {
            return true;
        }
    }
    result = NULL;
    return false;
}

跟TryDequeue()方法相似。

int Count()

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()


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()


void Reset()
{
    DeleteNodes();
    m_base = m_head = m_tail = new Segment(0);
}

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

void GetHeadTailPositions(Segment** head, Segment** tail, int* headLow, int* tailHigh)

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索引取出来,放到线程栈上。并且在取出这些值后,再判断这些值是否合法。

原文地址:http://www.cnblogs.com/quark/archive/2012/03/19/2406024.html

目录
相关文章
|
5月前
|
存储 缓存 Java
9.队列:生产消费模式及线程池的运用
9.队列:生产消费模式及线程池的运用
55 0
|
Java 调度
多线程学习(三)那些队列可用于线程池
多线程学习(三)那些队列可用于线程池
87 0
|
5月前
|
安全
python_threading多线程、queue安全队列
python_threading多线程、queue安全队列
48 2
|
2月前
|
存储 监控 Java
|
2月前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
3月前
|
设计模式 安全 Java
Java面试题:请解释Java中的线程池以及为什么要使用线程池?请解释Java中的内存模型以及如何避免内存泄漏?请解释Java中的并发工具包以及如何实现一个简单的线程安全队列?
Java面试题:请解释Java中的线程池以及为什么要使用线程池?请解释Java中的内存模型以及如何避免内存泄漏?请解释Java中的并发工具包以及如何实现一个简单的线程安全队列?
36 1
|
3月前
|
设计模式 安全 NoSQL
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
45 0
|
5月前
|
设计模式 安全 Java
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)
Java 多线程系列Ⅳ(单例模式+阻塞式队列+定时器+线程池)
|
5月前
|
存储 安全 Java
Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列
Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列
|
5月前
|
Java
提交任务时,线程池队列已满,这时会发生什么
提交任务时,线程池队列已满,这时会发生什么