DIOCP开源项目-Delphi高性能无锁队列(lock-free)
最近想在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)的更多相关文章
- 高性能无锁队列 Disruptor 初体验
原文地址: haifeiWu和他朋友们的博客 博客地址:www.hchstudio.cn 欢迎转载,转载请注明作者及出处,谢谢! 最近一直在研究队列的一些问题,今天楼主要分享一个高性能的队列 Disr ...
- DIOCP开源项目-高效稳定的服务端解决方案(DIOCP + 无锁队列 + ZeroMQ + QWorkers) 出炉了
[概述] 自从上次发布了[DIOCP开源项目-利用队列+0MQ+多进程逻辑处理,搭建稳定,高效,分布式的服务端]文章后,得到了很多朋友的支持和肯定.这加大了我的开发动力,经过几个晚上的熬夜,终于在昨天 ...
- EasyDarwin开源流媒体服务器高性能设计之无锁队列
本文来自EasyDarwin团队Fantasy(fantasy(at)easydarwin.org) 一. EasyDarwin任务队列实现 EasyDarwin的任务队列是通过OSQueue类来组织 ...
- 基于无锁队列和c++11的高性能线程池
基于无锁队列和c++11的高性能线程池线程使用c++11库和线程池之间的消息通讯使用一个简单的无锁消息队列适用于linux平台,gcc 4.6以上 标签: <无> 代码片段(6)[ ...
- boost 无锁队列
一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久 ...
- 无锁队列--基于linuxkfifo实现
一直想写一个无锁队列,为了提高项目的背景效率. 有机会看到linux核心kfifo.h 原则. 所以这个实现自己仿照,眼下linux我们应该能够提供外部接口. #ifndef _NO_LOCK_QUE ...
- folly无锁队列正确性说明
folly无锁队列是facebook开源的一个无所队列,使用的是单向链表,通过compare_exchange语句实现的多生产多消费的队列,我曾经花了比较多的时间学习memory_order的说明,对 ...
- folly无锁队列,尝试添加新的函数
1. folly是facebook开源的关于无锁队列的库,实现过程很精妙.folly向队列中添加节点过程,符合标准库中的队列的设计,而取出节点的过程,则会造成多个线程的分配不均.我曾经试着提供一次 取 ...
- Erlang运行时中的无锁队列及其在异步线程中的应用
本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过“线程进度”机制解决无锁队列的问题,并介绍 Erlang ...
随机推荐
- 【TP3.2】TP3.2的 FIND_IN_SET()的用法
1.mysql的find_in_set 用法我这里就不介绍了,很好用的一个方法. 2.TP3.2使用: $where['_string'] = 'FIND_IN_SET('."'$id'&q ...
- Javascript中类型的判断
数据类型的判断有这么几种方式 1.一元运算符 typeOf 2.关系运算符 instanceof 3.constructor 属性 4.prototype属性 一.typeof typeof的返回值有 ...
- seaweedfs 源码笔记(一)
seaweedfs中的名词:master: 存储文件和fid映射关系volumn:实际存储文件datacenter: 数据中心rack: 机架.一个机架属于特定的数据中心,一个数据中心可以包含多个机架 ...
- [Spring学习笔记 3 ] spring 注解详解,完全注解,常用注解
.xml使用注解 xml 用来定义bean的信息,注解用来配置依赖信息 ) 在配置文件中配置bean )在javaBean中用注解来指定依赖注入 )在配置文件中开启注解扫描 @Resource标签 j ...
- 【LeetCode】173. Binary Search Tree Iterator (2 solutions)
Binary Search Tree Iterator Implement an iterator over a binary search tree (BST). Your iterator wil ...
- POJ 3207 Ikki's Story IV - Panda's Trick (2-sat)
Ikki's Story IV - Panda's Trick Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 6691 ...
- JetBrains C++ IDE CLion配置与评测
等了大半年的JetBrains C++ IDE千呼万唤始出来!上次我猜2014年肯定发布,今天经@wet2_cn同学的提醒,我去官博一看,嘿!有了!赶紧安装试了一把,感觉这是迄今为止用过最好的Cpp ...
- linux 免输入密码脚本
#! /usr/bin/expectset command [lindex $argv 0]set passwd [lindex $argv 1]spawn su - root -c $command ...
- JavaScript语言精粹--replace()与正则
今天有人问我repalce(),他那个题目很有意思.我也不会做,于是我就去查,结果发现就是最基础的知识的延伸. 所以啊最基础的知识才是很重要的,千万不能忽略,抓起JS就写代码完全不知到所以然,只知道写 ...
- 史上最简单的 GitHub 教程
史上最简单的 GitHub 教程 温馨提示:本系列博文已经同步到 GitHub,如有需要的话,欢迎大家到「github-tutorial」进行Star和Fork操作! 1 简介 GitHub 是一个面 ...