本文提供Delphi一个基于原子操作的无锁队列,简易高效。适用于多线程大吞吐量操作的队列。

可用于Android系统和32,64位Windows系统。

感谢歼10和qsl提供了修改建议!

有如下问题:

1.必须事先足够大开辟内存,大到不会出现队列溢出了。

2.队列大小必须是2的幂

3.不能压入空指针

4.本程序还未经过工程应用考验

  1. unit Iocp.AtomQueue;
  2.  
  3. interface
  4.  
  5. Uses
  6. SysUtils,
  7. SyncObjs;
  8.  
  9. Type
  10. TAtomFIFO = Class
  11. Protected
  12. FWritePtr: Integer;
  13. FReadPtr: Integer;
  14. FCount:Integer;
  15. FHighBound:Integer;
  16. FisEmpty:Integer;
  17. FData: array of Pointer;
  18. function GetSize:Integer;
  19. Public
  20. procedure Push(Item: Pointer);
  21. function Pop: Pointer;
  22. Constructor Create(Size: Integer); Virtual;
  23. Destructor Destroy; Override;
  24. Procedure Empty;
  25. property Size: Integer read GetSize;
  26. property UsedCount:Integer read FCount;
  27. End;
  28.  
  29. Implementation
  30.  
  31. //创建队列,大小必须是2的幂,需要开辟足够大的队列,防止队列溢出
  32.  
  33. Constructor TAtomFIFO.Create(Size: Integer);
  34. var
  35. i:NativeInt;
  36. OK:Boolean;
  37. Begin
  38. Inherited Create;
  39. OK:=(Size and (Size-)=);
  40.  
  41. if not OK then raise Exception.Create('FIFO长度必须大于等于256并为2的幂');
  42.  
  43. try
  44. SetLength(FData, Size);
  45. FHighBound:=Size-;
  46. except
  47. Raise Exception.Create('FIFO申请内存失败');
  48. end;
  49. End;
  50.  
  51. Destructor TAtomFIFO.Destroy;
  52. Begin
  53. SetLength(FData, );
  54. Inherited;
  55. End;
  56.  
  57. procedure TAtomFIFO.Empty;
  58. begin
  59. while (TInterlocked.Exchange(FReadPtr, )<>) and
  60. (TInterlocked.Exchange(FWritePtr, )<>) and
  61. (TInterlocked.Exchange(FCount, )<>) do;
  62. end;
  63.  
  64. function TAtomFIFO.GetSize: Integer;
  65. begin
  66. Result:=FHighBound+;
  67. end;
  68.  
  69. procedure TAtomFIFO.Push(Item:Pointer);
  70. var
  71. N:Integer;
  72. begin
  73. if Item=nil then Exit;
  74.  
  75. N:=TInterlocked.Increment(FWritePtr) and FHighBound;
  76. FData[N]:=Item;
  77. TInterlocked.Increment(FCount);
  78. end;
  79.  
  80. Function TAtomFIFO.Pop:Pointer;
  81. var
  82. N:Integer;
  83. begin
  84. if TInterlocked.Decrement(FCount)< then
  85. begin
  86. TInterlocked.Increment(FCount);
  87. Result:=nil;
  88. end
  89. else
  90. begin
  91. N:=TInterlocked.Increment(FReadPtr) and FHighBound;
  92. //假设线程A调用了Push,并且正好是第1个push,
  93. //执行了N:=TInterlocked.Increment(FWritePtr) and FHighBound,
  94. //还没执行FData[N]:=Item, 被切换到其他线程
  95. //此时假设线程B调用了Push,并且正好是第2个push,并且执行完毕,这样出现FCount=1,第2个Item不为空,而第一个Item还是nil(线程A还没执行赋值)
  96. //假设线程C执行Pop,由于Count>0(线程B的作用)所以可以执行到这里,但此时FData[N]=nil(线程A还没执行赋值),
  97. //因此线程C要等待线程A完成FData[N]:=Item后,才能取走FData[N]
  98. //出现这种情况的概率应该比较小,基本上不会浪费太多CPU
  99. while FData[N]=nil do Sleep();
  100. Result:=FData[N];
  101.  
  102. FData[N]:=nil;
  103. end;
  104. end;
  105.  
  106. End.

性能测试:

采用天地弦提供的评估程序,进行了一些修改,分别对使用不同的临界区的队列进行对比结果如下:

其中Swith是因队列读空,进行线程上下文切换的次数

  1.  

简易高效的Delphi原子队列的更多相关文章

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

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

  2. c#高效的线程安全队列ConcurrentQueue<T>(上)

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

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

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

  4. Git学习总结(5)——搭建Git简易高效服务器

    1. mysysgit+gitblit安装流程 1.1资源  需先下载好的资源(公司用的1.6,1.7+请自行匹配对应的mysysgit+gitblit):  jdk1.6  Git-1.8.4-pr ...

  5. 高效C++无锁队列实现-moodycamel::ConcurrentQueue

    国外一牛人做的,支持多平台,支持多线程写.多线程读,并可指定读写token,转载过来. 感觉作者也时刻维护着他这个项目,我提了一些问题,每次都会及时得到答复,而且回复得非常认真仔细,非常赞! 链接地址 ...

  6. Delphi 高效读写锁

    本人设计了一个高效读写锁,可实现多个线程读一个线程写的锁,应该比Delphi自带的读写锁高效,本人没有做对比测试. 本文的锁不可以在一个线程里重入,否则会锁死,另外读写锁最多支持65535个线程同时读 ...

  7. disruptor 高效队列

    disruptor 是什么: disruptor 是一个 低延时的 无锁 环形 队列.  相较于 java的 队列 ,他有明显的优点  ,无界,无锁,低延时(解决了为内存共享问题 ) disrupto ...

  8. [Java] 集合框架原理之二:锁、原子更新、线程池及并发集合

    java.util.concurrent 包是在 Java5 时加入的,与 concurrent 的相关的有 JMM及 AbstractQueuedSynchronizer (AQS),两者是实现 c ...

  9. XP局域网内专用消息队列

    网上能找到DELPHI消息队列的方法,在XP下试了总是不成功,后来在2003上试就行了,对比发现消息队列属性->安全 2003中多了个用户ANONYMOUS_LOGON. 然后在XP下消息队列属 ...

随机推荐

  1. 在小程序中修改上一个页面里data中的数据调用上一个页面的方法

    //获取已经打开的页面的数组 var pages = getCurrentPages(); //获取上一个页面的所有的方法和data中的数据  var lastpage = pages[pages.l ...

  2. iis7 未注册framework4 导致 莫名的404错误

    server2008  R2 IIS7 已经安装 安装framework 4.6.1 然后建立站点 404错误 :在站点目录自动生成了  asp_client 重新注册到 iis(不需要) iisre ...

  3. January 09 2017 Week 2nd Monday

    Patience is bitter, but its fruit is sweet. 忍耐是痛苦的,但它的果实是甜蜜的. Some patience may be just fruitless, o ...

  4. redis下的adlist

    //adlist.h #ifndef __ADLIST__H__ #define __ADLIST__H__ typedef struct listNode_ { struct listNode_ * ...

  5. facebook开源的代码审核工具phabricator

    主页地址:http://phabricator.org/

  6. PhoneGap 介绍

    一.PhoneGap 是什么 1.PhoneGap 是一个用基于 HTML,CSS 和 JavaScript 的,创建移动跨平台移动应用程序的快速开发框架. 2.它使开发者能够利用 iPhone,An ...

  7. 操作dict时避免出现KeyError的几种方法

    在读取dict的key和value时,如果key不存在,就会触发KeyError错误,如: Python t = { ', ', ', } print(t['d']) 就会出现: <code c ...

  8. Python中的类(一)

    Python中的类(一) 一. 应用场景 如果多个函数中有一些相同的参数时,转换成面向对象. 二. 如何创建类 类是用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法 ...

  9. C/C++——指针,引用做函数形参

    函数中的形参是普通形参的时,函数只是操纵的实参的副本,而无法去修改实参. 引用形参是对实参的直接操纵,指针形参是对 它所指向的值(*p) 的直接操纵,但是对于这个指针变量(p)来说,依然只是副本. 指 ...

  10. programming-languages学习笔记--第7部分

    programming-languages学习笔记–第7部分 */--> pre.src {background-color: #292b2e; color: #b2b2b2;} pre.src ...