c# 高效的线程安全队列ConcurrentQueue(下) Segment类
Segment成员变量
long long m_index;
记录该segment的索引号。
int* volatile m_state;
状态数组,标识所对应的元素节点的状态,默认值为0,如果该元素节点添加了值,则标记为1。
T* volatile m_array;
队列元素存储空间的指针。
Segment* volatile m_next;
指向下一个segment的指针。
volatile long m_high;
标识在当前segment,元素最后添加的索引值,初始值为-1,如果该segment被填满了,则该值为SEGMENT_SIZE – 1。
volatile long m_low;
标识在当前segment,元素最后取出位置的索引值,初始值为0,如果该segment一个都没有取走元素,则该值为0。如果m_low >m_high,表示该segment为空。
Segment成员函数
void Grow(Segment* volatile* tail)
|
1
2
3
4
5
6
|
void Grow(Segment* volatile* tail){ Segment* segment = new Segment(m_index + 1); m_next = segment; *tail = m_next;} |
|
1
|
创建下一个segment,并将tail指针指向新创建的segment; |
bool TryAppend(T value, Segment* volatile * tail)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
bool TryAppend(T value, Segment* volatile * tail){ if (m_high >= SEGMENT_SIZE - 1) { return false; } int index = SEGMENT_SIZE; index = InterlockedIncrement(&m_high); if (index <= SEGMENT_SIZE - 1) { m_array[index] = value; m_state[index] = 1; } if (index == SEGMENT_SIZE - 1) { Grow(tail); } return (index <= SEGMENT_SIZE - 1);} |
往当前segment里面,增加一个元素,如果添加满了,就创建下一个segment。
bool TryPeek(T* result)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
bool TryPeek(T* result){ int low = GetLow(); if (low > GetHigh()) { return false; } DNetSpinWait wait; while (m_state[low] == 0) { wait.SpinOnce(); } *result = m_array[low]; return true;} |
如果segment为空,返回false,否则,返回low所在位置的值。
bool TryRemove(T* result, Segment* volatile * head)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
bool TryRemove(T* result, Segment* volatile * head){ DNetSpinWait wait; int low = GetLow(); for (int i = GetHigh(); low <= i; i = GetHigh()) { if (InterlockedCompareExchange(&m_low, low + 1, low) == low) { DNetSpinWait wait2; while (m_state[low] == 0) { wait2.SpinOnce(); } *result = m_array[low]; if ((low + 1) >= SEGMENT_SIZE) { wait2.Reset(); while (m_next == NULL) { wait2.SpinOnce(); } *head = m_next; } return true; } wait.SpinOnce(); low = GetLow(); } result = NULL; return false;} |
这是最复杂的一个方法。利用了InterlockedCompareExchange方法,该方法的解释:
LONG __cdecl InterlockedCompareExchange(
__inout LONG volatile* Destination,
__in LONG Exchange,
__in LONG Comparand
);
Parameters
Destination
A pointer to the destination value. The sign is ignored.
Exchange
The exchange value. The sign is ignored.
Comparand
The value to compare to Destination. The sign is ignored.
Return Value
The function returns the initial value of the Destination parameter.
通过自旋来保证线程同步。
int GetHigh()
{
return min(m_high, SEGMENT_SIZE - 1);
}
bool IsEmpty()
{
return m_low > m_high;
}
int GetLow()
{
return min(m_low, SEGMENT_SIZE);
}
Segment* GetNext()
{
return m_next;
}
long long GetIndex()
{
return m_index;
}
c# 高效的线程安全队列ConcurrentQueue(下) Segment类的更多相关文章
- c# 高效的线程安全队列ConcurrentQueue
c#高效的线程安全队列ConcurrentQueue<T>(上) c# 高效的线程安全队列ConcurrentQueue(下) Segment类 c#高效的线程安全队列Concurrent ...
- c#高效的线程安全队列ConcurrentQueue<T>(上)
ConcurrentQueue<T>队列是一个高效的线程安全的队列,是.Net Framework 4.0,System.Collections.Concurrent命名空间下的一个数 ...
- C#数据结构-线程安全队列
什么是线程安全? 答:线程安全是多线程编程时的计算机程序代码中的一个概念.在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意 ...
- C#-----线程安全的ConcurrentQueue<T>队列
ConcurrentQueue<T>队列是一个高效的线程安全的队列,是.Net Framework 4.0,System.Collections.Concurrent命名空间下的一个数据 ...
- 线程安全的ConcurrentQueue<T>队列
队列(Queue)代表了一个先进先出的对象集合.当您需要对各项进行先进先出的访问时,则使用队列.当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队. ConcurrentQueue< ...
- [一起读源码]走进C#并发队列ConcurrentQueue的内部世界
决定从这篇文章开始,开一个读源码系列,不限制平台语言或工具,任何自己感兴趣的都会写.前几天碰到一个小问题又读了一遍ConcurrentQueue的源码,那就拿C#中比较常用的并发队列Concurren ...
- 线程池 队列 synchronized
线程池 BlockingQueue synchronized volatile 本章从线程池到阻塞队列BlockingQueue.从BlockingQueue到synchronized 和 volat ...
- 生产消费模式:多线程读写队列ConcurrentQueue
需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子. 直接上代码,看下实现: // 初始化列队缓冲区 队列大小为100 IDataCollection<List&l ...
- Linux多线程系列-2-条件变量的使用(线程安全队列的实现)
多线程情况下,往往需要使用互斥变量来实现线程间的同步,实现资源正确共享. linux下使用如下变量和函数 //条件变量 pthread_cond_t int pthread_cond_init (pt ...
随机推荐
- wpf4 文字 模糊 不清晰 解决方法
在窗口或控件上设置字体属性就可以了,如下:<UserControl x:Class="..." xmlns="http://schemas. ...
- 通过网络方式安装linux的五种方法
在线观看:http://video.sina.com.cn/v/b/43086503-1443650204.html http://video.sina.com.cn/v/b/43095530-144 ...
- T-SQL 批处理
批处理简介 批处理是作为一个逻辑单元的T-SQL语句.如果一条语句不能通过语法分析,那么不会运行任何语句.如果一条语句在运行时失败,那么产生错误的语句之前的语句都已经运行了. 为了将一个脚本分为多个批 ...
- cocos2d-x中有一个JniHelper类详细使用
主体思路 通过JNI获取java虚拟机,再获取当前程序的JNI环境,通过JNI环境获取需要调用的java类信息,再获取需要调用的java类中的函数信息.再通过JNI环境调用,使用类信息.函数信息,调用 ...
- Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset (0/1-Trie树)
Vasiliy's Multiset 题目链接: http://codeforces.com/contest/706/problem/D Description Author has gone out ...
- C++ __int64用法(转)
在做ACM题时,经常都会遇到一些比较大的整数.而常用的内置整数类型常常显得太小了:其中long 和 int 范围是[-2^31,2^31),即-2147483648~2147483647.而unsig ...
- EntityFramework简单例子
@(编程) 这个例子是用vs2013连接mysql数据库. 1. NuGet安装EF和mysql 略 2. 对象 namespace EFDemo { class Student { public s ...
- TdxAlertWindowManager右下角HINT显示控件
带爱像的右下角HINT显示,自动隐藏 function alterInfo: TdxAlertWindowManager;begin if not Assigned(Falter) then be ...
- CTE初识
微软从SQl2005起引入了CTE(Common Table Expression)以强化T-SQL.这是一个类似于非持久视图的好东西. 正常的SQL语句: select * from person. ...
- 几种连接不同数据库的ADO.NET字符串
Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;或者 Ser ...