目录

ring库

FreeBSD *中的Ring实施参考

Linux *中的无锁环形缓冲区

附加功能

名称

用例

环形缓冲区的解剖

单一生产者入队

单一消费者出队

多个生产者入队

模数32位索引

生产者/消费者同步模式

MP / MC(默认一项)

SP / SC

MP_RTS / MC_RTS

MP_HTS / MC_HTS

环窥API

参考资料


ring库

环允许管理队列。除了具有无限大小的链表之外,rte_ring具有以下属性:

  • 先进先出
  • 最大大小是固定的,对象存储在表中
  • 对象可以是指针或4字节大小倍数的元素
  • 无锁实现
  • 多消费者或单消费者出队
  • 多生产者或单生产者入队
  • 批量出队-如果成功,则使指定数量的对象出队;否则失败
  • 批量入队-如果成功,则使指定数量的对象入队;否则失败
  • 突发出队-如果无法满足指定的计数,则出队最大可用对象
  • 突发入队-如果无法满足指定的数量,则排入最大可用对象

与链接列表队列相比,此数据结构的优点如下:

  • 快点; 只需要一个32位的Compare-And-Swap指令,而不是几个指针大小的Compare-And-Swap指令。
  • 比完整的无锁队列简单。
  • 适用于批量入队/出队操作。当对象存储在表中时,多个对象的出队将不会产生与链接队列中一样多的高速缓存未命中。同样,许多对象的批量出队不比简单对象的出队花费更多。

缺点:

  • 大小是固定的
  • 就内存而言,拥有多个环比链接列表队列要花费更多。一个空环至少包含N个对象。

图中显示了Ring的简化表示,其中消费者和生产者的头和尾指针指向存储在数据结构中的对象。

rte_ring结构体


/*** An RTE ring structure.** The producer and the consumer have a head and a tail index. The particularity* of these index is that they are not between 0 and size(ring). These indexes* are between 0 and 2^32, and we mask their value when we access the ring[]* field. Thanks to this assumption, we can do subtractions between 2 index* values in a modulo-32bit base: that's why the overflow of the indexes is not* a problem.*/
struct rte_ring {/** Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI* compatibility requirements, it could be changed to RTE_RING_NAMESIZE* next time the ABI changes*/char name[RTE_MEMZONE_NAMESIZE] __rte_cache_aligned; /**< Name of the ring. */int flags;               /**< Flags supplied at creation. */const struct rte_memzone *memzone;/**< Memzone, if any, containing the rte_ring */uint32_t size;           /**< Size of ring. */uint32_t mask;           /**< Mask (size-1) of ring. */uint32_t capacity;       /**< Usable size of ring */char pad0 __rte_cache_aligned; /**< empty cache line *//** Ring producer status. */struct rte_ring_headtail prod __rte_cache_aligned;char pad1 __rte_cache_aligned; /**< empty cache line *//** Ring consumer status. */struct rte_ring_headtail cons __rte_cache_aligned;char pad2 __rte_cache_aligned; /**< empty cache line */
};

FreeBSD *中的Ring实施参考

以下代码已添加到FreeBSD 8.0中,并在某些网络设备驱动程序中使用(至少在Intel驱动程序中使用):

  • FreeBSD中的bufring.h
  • FreeBSD中的bufring.c

Linux *中的无锁环形缓冲区

以下是描述Linux无锁环形缓冲区设计的链接。

附加功能

名称

环由唯一名称标识。无法创建两个具有相同名称的环(如果尝试这样做,rte_ring_create()将返回NULL)。

用例

Ring库的用例包括:

  • DPDK中的应用程序之间的通信
  • 由内存池分配器使用

环形缓冲区的解剖

本节说明环形缓冲区的工作方式。环形结构由两个头对和尾对组成。一种由生产者使用,另一种由消费者使用。以下各节的图将它们称为prod_head,prod_tail,cons_head和cons_tail。

每个图代表环的简化状态,它是一个圆形缓冲区。函数局部变量的内容显示在图的顶部,而环结构的内容显示在图的底部。

单一生产者入队

本节说明生产者将对象添加到环时会发生什么。在此示例中,仅修改了生产者的头和尾(prod_head和prod_tail),并且只有一个生产者。

初始状态是使prod_head和prod_tail指向同一位置。

入队第一步

首先,将ring-> prod_head和ring-> cons_tail复制到局部变量中。prod_next局部变量指向表的下一个元素,或者在批量入队的情况下指向多个元素。

如果环中没有足够的空间(通过检查cons_tail可以检测到),它将返回错误。

入队第二步

第二步是修改环结构中的ring-> prod_head以指向与prod_next相同的位置。

添加的对象被复制到环(obj4)中。

入队最后一步

将对象添加到环中后,将修改环结构中的ring-> prod_tail使其指向与ring-> prod_head相同的位置。入队操作完成。

单一消费者出队

本节说明了当使用者将对象从环中出队时会发生什么。在此示例中,仅修改了消费者的头和尾(cons_head和cons_tail),并且只有一个消费者。

初始状态是使cons_head和cons_tail指向同一位置。

出队第一步

首先,将ring-> cons_head和ring-> prod_tail复制到局部变量中。cons_next局部变量指向表的下一个元素,或者在批量出队的情况下指向多个元素。

如果环中没有足够的对象(通过检查prod_tail可以检测到),它将返回错误。

出队第二步

第二步是修改ring结构中的ring-> cons_head以指向与cons_next相同的位置。

出队对象(obj1)复制到用户给定的指针中。

出队最后一步

最后,将ring结构中的ring-> cons_tail修改为指向与ring-> cons_head相同的位置。出队操作完成。

多个生产者入队

本节说明当两个生产者同时将对象添加到环时会发生什么。在此示例中,仅修改了生产者的头和尾(prod_head和prod_tail)。

初始状态是使prod_head和prod_tail指向同一位置。

多个生产者进入第一步

在两个内核上,ring-> prod_head和ring-> cons_tail都复制到局部变量中。prod_next局部变量指向表的下一个元素,或者在批量入队的情况下指向多个元素。

如果环中没有足够的空间(通过检查cons_tail可以检测到),它将返回错误。

多个生产者加入第二步

第二步是修改ring结构中的ring-> prod_head以指向与prod_next相同的位置。此操作使用“比较和交换”(CAS)指令完成,该指令自动执行以下操作:

  • 如果ring-> prod_head与局部变量prod_head不同,则CAS操作失败,并且代码在第一步重新启动。
  • 否则,将ring-> prod_head设置为本地prod_next,CAS操作成功,然后继续处理。

在该图中,操作在内核1上成功完成,而第一步在内核2上重新启动。

多个生产商加入第三步

成功在核心2上重试CAS操作。

核心1更新了ring(obj4)的一个元素,核心2更新了另一个(obj5)的元素。

多个生产者进入第四步

每个内核现在都想更新ring-> prod_tail。仅当ring-> prod_tail等于prod_head局部变量时,内核才能更新它。这仅在内核1上成立。操作已在内核1上完成。

多个生产者进入最后一步

内核1更新了ring-> prod_tail之后,内核2也可以对其进行更新。该操作也已在核心2上完成。


模数32位索引

在前面的图中,prod_head,prod_tail,cons_head和cons_tail索引由箭头表示。在实际的实现中,这些值不介于0和size(ring)-1之间,如所假设的那样。索引在0到2 ^ 32 -1之间,访问对象表(环本身)时,我们会屏蔽它们的值。32位模还意味着如果结果超出32位数字范围,对索引的操作(例如加/减)将自动执行2 ^ 32模。

以下是两个示例,有助于说明如何在环中使用索引。

注意:为了简化说明,使用16位模运算而不是32位模运算。另外,这四个索引被定义为无符号的16位整数,而在更实际的情况下,这是无符号的32位整数。

Modulo 32位索引-示例1

该环包含11000个条目。

模32位索引-示例2

该环包含12536个条目。

注意:为了便于理解,我们在上述示例中使用65536模运算。在实际执行情况下,这对于降低效率是多余的,但是当结果溢出时会自动完成。

该代码始终将生产者和消费者之间的距离保持在0到size(ring)-1之间。由于具有此属性,我们可以在32位模的基础上进行2个索引值之间的减法:这就是为什么索引溢出不是问题。

在任何时候,即使只有第一项减法已溢出,entry和free_entries仍在0到size(ring)-1之间。

uint32_t  item =  (prod_tail  -  cons_head );
uint32_t  free_entries  =  (mask  +  cons_tail  - prod_head );

生产者/消费者同步模式

rte_ring为生产者和消费者支持不同的同步模式。这些模式可以在振铃创建/初始化时通过flags 参数指定。这应该可以帮助用户以最适合其特定使用场景的方式配置铃声。当前支持的模式:

MP / MC(默认一项)

多生产者(/多消费者)模式。这是环网的默认入队(/出队)模式。在此模式下,多个线程可以将对象排入(/出队)到环(/从环)。对于“经典” DPDK部署(每个内核只有一个线程),这通常是最合适,最快的同步模式。作为一个众所周知的局限性,它可以在某些过度使用的情况下执行纯粹的操作。

SP / SC

单生产者(/单消费者)模式。在此模式下,一次仅允许一个线程将对象排队(或从队列中取出)。

MP_RTS / MC_RTS

具有轻松尾部同步(RTS)模式的多生产者(/多消费者)。与原始MP / MC算法的主要区别在于,尾值不会由每个完成入队/出队的线程增加,而只会由最后一个线程增加。这样一来,线程就可以避免旋转环尾值,而将给定实例的实际尾值更改留给最后一个线程。该技术有助于避免在更新尾部时出现“锁定等待抢占”(LWP)问题,并改善了过量使用系统上的平均入队/出队时间。为了实现RTS,每个入队(/出队)操作需要2个64位CAS:一个用于头部更新,第二个用于尾部更新。相比之下,原始的MP / MC算法需要一个32位CAS来进行磁头更新和尾值的等待/旋转。

MP_HTS / MC_HTS

具有头/尾同步(HTS)模式的多生产者(/多消费者)。在这种模式下,入队/出队操作已完全序列化:在任何给定时刻,只能进行一次入队/出队操作。这是通过允许线程head.value 仅在时才进行更改来实现的。头部和尾部的值都自动更新(作为一个64位值)。为了实现这一点,头部更新例程将使用64位CAS。该技术还避免了在尾部更新时发生的“锁定等待抢占”(LWP)问题,并有助于在过量使用的情况下改善环入队/出队行为。完全序列化的生产者/消费者的另一个优点-它提供了为rte_ring实施MT安全查看API的能力。head.value == tail.value

环窥API

对于具有序列化生产者/消费者(HTS同步模式)的环,可以将公共入队/出队API分为两个阶段:

  • 入队/出队开始
  • 入队/出队完成

这样,用户就可以检查环中的对象而无需将其从环中移除(又名MT安全偷看),并在实际入队之前为环中的对象保留空间。请注意,此API仅适用于两种同步模式:

  • 单一生产者/单一消费者(SP / SC)
  • 具有头/尾同步(HTS)的多生产者/多消费者

用适当的同步模式创建/初始化振铃是用户的责任。作为用法示例:

/ *从环读取1个元素:* / 
uint32_t  n  =  rte_ring_dequeue_bulk_start (ring , &obj , 1 , NULL );
if  (n  !=  0 ) { / *检查对象* / if  (object_examine (obj ) ==  KEEP )/ *决定将其保留在环中。* / rte_ring_dequeue_finish (ring , 0 ); 否则/ *决定将其从环中删除。* / rte_ring_dequeue_finish (铃声, n );
}

请注意,在_start_和之间_finish_没有其他线程可以继续进行enqueue(/ dequeue)操作,直到_finish_完成。

参考资料

  • FreeBSD(版本8)中的bufring.h
  • FreeBSD(版本8)中的bufring.c
  • Linux无锁环形缓冲区设计

相关文章

https://rtoax.blog.csdn.net/article/details/107086652

DPDK ring库:环形缓冲区的解剖相关推荐

  1. Ring Buffer (circular Buffer)环形缓冲区简介

    https://blog.csdn.net/langeldep/article/details/8888582 关于环形缓冲区的知识,请看这里 http://en.wikipedia.org/wiki ...

  2. 环形缓冲区的实现原理(ring buffer)

    消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了.频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行.也许我们可以 ...

  3. SQL Server 环形缓冲区(Ring Buffer) -- 介绍

    SQL Server 环形缓冲区(Ring Buffer) -- 介绍 以下关于Ring Buffer的介绍转载自: http://zh.wikipedia.org/wiki/%E7%92%B0%E5 ...

  4. SQL Server 环形缓冲区(Ring Buffer) -- 环形缓冲在AlwaysOn的应用

    SQL Server 环形缓冲区(Ring Buffer) -- 环形缓冲在AlwaysOn的应用 可以从SQL Server环形缓冲区得到一些诊断AlwaysOn的信息,或从sys.dm_os_ri ...

  5. 环形缓冲区(Ring Buffer)使用说明

    本说明涉及如下内容 什么是环形缓冲区 如何使用环形缓冲区 函数调用说明 环形缓冲区源码下载地址https://download.csdn.net/download/xm_smallp/86248489 ...

  6. 优秀的内存规划方法——环形缓冲区(ring buffer)

    目录 什么是环形缓冲区 使用环形buffer的好处 环形buffer的使用场景 进程间通信 网络IO 区分缓冲区是满或者是空 计数 保持一个存储单元为空 镜像指示位 buffer满了之后的操作 实时流 ...

  7. 环形缓冲区实现(C语言)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 要求 一.环形缓冲区 二.环形缓冲区实现(C语言) 1. ringBuf.h 2. ringBufInit.c 3. rin ...

  8. 架构设计:生产者/消费者模式 第6页:环形缓冲区的实现

    2019独角兽企业重金招聘Python工程师标准>>> ◇判断"空"和"满" 上述的操作并不复杂,不过有一个小小的麻烦:空环和满环的时候,R和 ...

  9. 环形缓冲区ringbuffer

    环形缓冲区是生产者和消费者模型中常用的数据结构.生产者将数据放入数组的尾端,而消费者从数组的另一端移走数据,当达到数组的尾部时,生产者绕回到数组的头部. 如果只有一个生产者和一个消费者,那么就可以做到 ...

最新文章

  1. Kali Linux 安全渗透教程第四更1.3 Kali Linux简介
  2. redmine 一键安装
  3. JSValidation 配置文件
  4. 关于Qstring.replace传参Qstring.length为0引起程序退出的记录
  5. MySQL升级后 MySQL 5.7 时间不兼容问题
  6. Docker技术三大要点:cgroup, namespace和unionFS的理解
  7. LeetCode 366. 寻找二叉树的叶子节点(上下翻转二叉树+BFS)
  8. SpringBoot中使用Hibernate Validator校验工具类
  9. mysql 头行关联_mysql实现一样变多行(表关联,批量实现)
  10. 【调试手段】:printf统一为宏控制
  11. C#实现图像下一张上一张
  12. learn git 廖雪峰GIT教材1 创建与合并分支
  13. linux导入表dmp文件命令,linux下导入.dmp文件
  14. 2023计算机考研专业课参考书目(408)
  15. 演讲稿【物性的神奇】
  16. P1931 套利-SPFA最长路与环的判断
  17. SATA电源线的作用
  18. 币值最大化问题 C++C++
  19. PCL中点云特征描述与提取精通级实例解析
  20. python 打印三角形

热门文章

  1. maven添加jar包依赖
  2. 2019.7.25锻炼逻辑思维9道题。
  3. 团队第一阶段冲刺——第七天
  4. BJOI2018 简要题解
  5. Oracle总结第一篇【基本SQL操作】
  6. BZOJ:4820: [Sdoi2017]硬币游戏BZOJ:1444: [Jsoi2009]有趣的游戏(高斯消元求概率)
  7. SSH远程登录原理与运用
  8. HEAP: Free Heap block xxxxxxxx modified at xxxxxxxx after it was freed
  9. 最短路径之dijkstra算法的C语言实现
  10. Linux中让普通用户拥有超级用户的权限