• DPDK ring简单说明


    1.ring提供的接口

    对于一个模块而言,其对外提供的接口直接表明了它所提供的功能,也是我们分析一个模块最初的入口。ring是一个环形无锁队列,支持多生产者多消费者操作,所以对于队列的操作构成了模块的主要接口。ring的实现在文件rte_ring.crte_ring.h中。

    rte_ring_create() //ring的创建
    
    rte_ring_init() //ring的初始化
    
    rte_ring_lookup() //ring的查找
    
    rte_ring_free() //ring的释放
    
    rte_ring_dump() //获取ring的使用信息
    
    rte_ring_set_water_mark() //设置ring的水标
    
    

    以上的几个大的接口提供了ring的开始和结束以及查找。同时对于一个队列来说,还有更多的入队,出队操作。如函数

    rte_ring_mp_enqueue_burst()//多生产者批量入队
    
    

    此处就省略其他很多单(多)生产者,单(多)消费者的操作函数接口了。

    2.ring的创建及初始化

    rte ring的创建是通过rte_ring_create()函数来实现的,这个函数的原型struct rte_ring * rte_ring_create(const char *name, unsigned count, int socket_id,unsigned flags)

    这里需要注意的是socket_idflags,在多个进程同时访问同一个ring时,要改善性能,可以创建多个ring,同时要注意多个进程绑定在同一个socket上。另一个参数flags则是表明创建的ring是否安全支持多生产者多消费者模型。接下来就来看看创建及初始化中的一些细节。

    首先找到ring_listring_list是挂接在队列中的,根据ring不跨socket的原则,推断是每个socket都维护有一个这样的队列,具体就不去抠代码了,先主后次。

    接下来就是两个准备操作:

    • 获取创建的ring的空间大小,为后面分配空间做准备。

    • 分配一个struct rte_tailq_entry *te;结构,在创建完成ring后,挂接这个队列元素到队列中去。此时不妨先看一下这个结构体的定义。

      struct rte_tailq_entry {
      	TAILQ_ENTRY(rte_tailq_entry) next; 
      	/**< Pointer entries for a tailq list */
      	void *data; /**< Pointer to the data referenced by this 	tailq entry */
      };
      

    其中的data指针就指向了创建的ring的地址。

    然后就是为新创建的ring分配内存空间咯,使用了rte_memzone_reserve()函数分配,这个函数在内存部分详细说明,但是需要注意:

    rte_memzone_reserve()只能用于primary进程中内存分配,也暗含了对于多生产者多消费者使用的ring,其ring的创建要在 primary进程中。

    最后就是把分配的ring初始化-rte_ring_init(),并填充te元素,把te挂接在队列中。

    3.ring的出入队

    ring的出入队操作,我们重点来关注几个接口:

    __rte_ring_mp_do_enqueue()
    __rte_ring_sp_do_enqueue()
    __rte_ring_mc_do_dequeue()
    __rte_ring_sc_do_dequeue()
    
    

    无论使用的哪个上层接口,最终调用的就是这4个函数。在使用多生产者多消费者时,函数中会有rte_pause()的操作,里面使用了__mm_pause()指令,看注释意思是避免忙等待,主要应用在短时的loops。至于具体的头和尾指针的移动,可以参考prog_guide中的ring一节,图文并茂。

    4.ring的使用范围以及潜在问题

    • 1.ring的调试信息在non_EAL线程中是不支持获取的。

    • 2.ring支持多生产者入队和多消费者出队,但是都是不可抢占的。不可抢占的意思是:

      • 一个线程在做多生产者入队操作,此时,禁止被另一个做多生产者入队的线程抢占。
      • 一个线程在做多消费者出队操作,此时,禁止被另一个做多消费者出队的县城抢占。

      这意味着如果两个线程在同一个core上操作,那么2th线程则必须等到1th线程调度后才能访问,因此,尽量不要在同一个core上对同一个ring做多生产者同时入队或者出队。更详细的说明,请参考 prog_guide 3.3.4章节。

    5.关于水标的使用

    在初始化ring的时候,可以设置对应的水标位置,但感觉它并未提供设置接口,用的地方不是很多。比如,当入队已经达到水标位置时,就可以返回对应的错误值,上层调用就可以做些处理。

    x.关于无锁队列的链接:

    无锁队列顶层设计

    无锁队列到底有没有锁

  • 相关阅读:
    旋转数组的最小数字
    二维数组中的查找问题--剑指offer面试题3
    百度软件开发实习生c++方向面经(一面)
    一些常考的智力题
    灵感闪现 篇 (一) 2d场景 3d 效果
    GameUnity 2.0 文档(四) 网格+四叉树 最优碰撞检测
    GameUnity 2.0 文档(三) 纸片人八方向
    GameUnity 2.0 文档(二) 纸片人系统
    GameUnity 2.0 文档(一) 事件机制
    GameUnity 2.0 发布倒计时
  • 原文地址:https://www.cnblogs.com/yhp-smarthome/p/6910756.html
Copyright © 2020-2023  润新知