最近想在DIOCP中加入任务调度线程,DIOCP的工作线程作为生产者(producer)将接受到的数据对象,投递到任务调度线程中,然后统一进行分配。然而这一切都需要一个队列, 这几天都在关注无锁队列。

[队列]

首先是一个队列,简单的队列就是,生产者把数据压入队列(push), 消费者通过队列Pop出数据进行处理。

简单的队列就是提供Push,和Pop函数。

我们用一个链表来存储数据。Head ->data01->data02...data_n->Tail, 每个数据块的结构如下

type
PVarQueueBlock = ^TVarQueueBlock;
TVarQueueBlock = packed record
value:Variant;
next:PVarQueueBlock;
end;

1.在进行Push压入数据时压入将Tail.next指向新压入的数据块, 然后用新的数据块做Tail

procedure TSimpleQueue.pushQueue(pvData: PVarQueueBlock);
begin
if FHead = nil then
begin
FHead = pvData;
FTail := FHead;
end else
begin
FTail.next := pvData;
FTail := pvData;
end;
Inc(FCount);
end;

2.在进行Pop数据时把Head数据块取出,然后用Head数据块指向的下一块当作Head.

function TSimpleQueue.popQueue: PVarQueueBlock;
var
lvTemp, lvRet:PVarQueueBlock;
begin
lvTemp := FHead;
if (lvTemp = nil) then
begin //没有任何可以Pop出的值
Result := nil;
exit;
end; //
FHead := FHead.next; Dec(FCount);
Result :=lvTemp;
end;

上面就是简单的队列

[无锁队列]

上面的实现的队列在多线程情况下是不安全的。如果要在多并发下队列要进行加锁,在push和pop时加锁也是一种办法。可以直接用临界就可以了,但是我们要做的是无锁队列

首先记住多并发设计规则:决不要假设任何代码会连续执行

上面的push操作

FTail.next := pvData;
FTail := pvData;

也许执行了FTail.next:=pvData后,会被另外的线程抢走,然后FTail进行了新的赋值,这样在进行FTail := pvData;这样整个数据链条就会被破坏。

如果这两行我们能一次行完成,这样就可以实现无锁操作了,这样我们需要引入原子操作.Interlocked中的函数。

说无锁其实不太确切,只是锁的粒度小了。我们是使用api的InterlockedCompareExchange函数来实现的。

查一下MSDN

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683560(v=vs.85).aspx

LONG __cdecl InterlockedCompareExchange(
_Inout_ LONG volatile *Destination,
_In_ LONG Exchange,
_In_ LONG Comparand
);

Parameters

Destination [in, out]

A pointer to the destination value.

Exchange [in]

The exchange value.

Comparand [in]

The value to compare to Destination.

Return value

The function returns the initial value of the Destination parameter.

大概解释一下。这个函数是比较后进行交换。第一个参数是要存放目的的数据,第二个是交换数据,第三个是比较数据(与第一个比较), 如果交换返回的数据和第三个参数一样。

这样就可以在push和pop一步完成。

这里贴出push的pop操作

procedure TVarQueue.pushQueue(pvData: PVarQueueBlock);
var
lvTemp:PVarQueueBlock;
lvPointer:Pointer;
begin
while True do
begin
lvTemp := FTail;
while lvTemp.next <> nil do lvTemp := lvTemp.next;
if InterlockedCompareExchangePointer(Pointer(lvTemp.next), Pointer(pvData), nil) = nil then
begin
break;
end;
end;
FTail := pvData;
Inc(FCount);
end;
function TVarQueue.popQueue: PVarQueueBlock;
var
lvTemp, lvRet:PVarQueueBlock;
lvPointer:Pointer;
begin
///为了方便 队列中始终保留一个FHead数据块
/// 也就是说FHead指向的下一个数据块才是第一个数据块
/// while True do
begin
lvTemp := FHead;
if (lvTemp = nil) or (lvTemp.next = nil) then
begin //没有任何可以Pop出的值
Result := nil;
exit;
end;
if InterlockedCompareExchangePointer(Pointer(FHead), lvTemp.next, lvTemp) = lvTemp then
begin
break;
end;
end;
Dec(FCount);
lvRet := lvTemp.next;
Result := lvRet;
lvTemp.next := nil;
Dispose(lvTemp);
//返回的是head.next
end;

后续我会上传完整的代码到DIOCP项目中。

如有漏洞,敬请指出。欢迎假如DIOCP群讨论

DIOCP开源项目-Delphi高性能无锁队列(lock-free)的更多相关文章

  1. 高性能无锁队列 Disruptor 初体验

    原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 最近一直在研究队列的一些问题,今天楼主要分享一个高性能的队列 Disr ...

  2. DIOCP开源项目-高效稳定的服务端解决方案(DIOCP + 无锁队列 + ZeroMQ + QWorkers) 出炉了

    [概述] 自从上次发布了[DIOCP开源项目-利用队列+0MQ+多进程逻辑处理,搭建稳定,高效,分布式的服务端]文章后,得到了很多朋友的支持和肯定.这加大了我的开发动力,经过几个晚上的熬夜,终于在昨天 ...

  3. EasyDarwin开源流媒体服务器高性能设计之无锁队列

    本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin任务队列实现 EasyDarwin的任务队列是通过OSQueue类来组织 ...

  4. 基于无锁队列和c++11的高性能线程池

    基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上   标签: <无>   代码片段(6)[ ...

  5. boost 无锁队列

    一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久 ...

  6. 无锁队列--基于linuxkfifo实现

    一直想写一个无锁队列,为了提高项目的背景效率. 有机会看到linux核心kfifo.h 原则. 所以这个实现自己仿照,眼下linux我们应该能够提供外部接口. #ifndef _NO_LOCK_QUE ...

  7. folly无锁队列正确性说明

    folly无锁队列是facebook开源的一个无所队列,使用的是单向链表,通过compare_exchange语句实现的多生产多消费的队列,我曾经花了比较多的时间学习memory_order的说明,对 ...

  8. folly无锁队列,尝试添加新的函数

    1. folly是facebook开源的关于无锁队列的库,实现过程很精妙.folly向队列中添加节点过程,符合标准库中的队列的设计,而取出节点的过程,则会造成多个线程的分配不均.我曾经试着提供一次 取 ...

  9. Erlang运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过“线程进度”机制解决无锁队列的问题,并介绍 Erlang ...

随机推荐

  1. 【mysql】数据库Schema的优化

    由于MySQL数据库是基于行(Row)存储的数据库,而数据库操作 IO 的时候是以 page(block)的方式,也就是说,如果我们每条记录所占用的空间量减小,就会使每个page中可存放的数据行数增大 ...

  2. shell脚本把一些请求量非常高的ip给拒绝掉

    需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉!并且每隔半小时把不再发起请求或者请求量很小的ip给解封.   假设:    1. 一分钟内请求量高于100次的IP视为不正常请求 ...

  3. IDEA导入项目jar包红线, cannot resolve symbol xxxx问题

    简单来说遇到的这种情况2种方式解决了, 不知道还有没有其他原因的. 1.reimport包 2.清缓存重启 针对1方法: a.确实不缺包: 可以先注释掉pom文件中的jar包, 此时idea会提示im ...

  4. Mac Apache Maven 配置

    1.配置准备工作 1)配置 Maven 准备工作 下载相关软件 apache-maven-3.5.3.zip Maven 官网 Maven for Mac 配置软件下载地址,密码:q9u3. Mave ...

  5. svn搭建本地服务端

    使用VisualSVN Server来完成,下载地址:https://www.visualsvn.com/server/download/ 我安装的版本是3.3.1,安装的时候选择了标准版本,另外一个 ...

  6. idea13注册机

    public class Keygen { /** * @param s * @param i * @param bytes * @return */ public static short getC ...

  7. sort_area_size,sort_area_retained_size

    sort_area_sizeoracle不建议设置sort_area_size参数.除非实例被配置成了共享服务器模式.默认值已经足够满足大多数OLTP系统.如果是OLAP.批任务.创建大的索引,可能需 ...

  8. Activity的onPause()、onStop()和onDestroy()里要做的事情

    onPause(): 当系统调用你的activity中的onPause(),从技术上讲,那意味着你的activity仍然处于部分可见的状态,当时大多数时候,那意味着用户正在离开这个activity并马 ...

  9. Win7 64bit 安装VisualSVN出现报错:Servic &#39;VisualSVN Server&#39; failed to start.解决的方法

    问题描写叙述: Win7 64bit 安装VisualSVN时出现报错: Servic 'VisualSVN Server' failed to start.Please check VisualSV ...

  10. Echarts 如何与 百度地图结合?

    官方demo:http://echarts.baidu.com/examples/editor.html?c=map-polygon 需要按顺序加载以下几个资源,然后就可以在echarts配置中使用 ...