(精简理解)DPDK的无锁环形队列Ring

1. DPDK Ring简介

dpdk实现了一个无锁环形队列Ring,可用于在dpdk不同的应用程序之间进行通信。

逻辑上ring看起来如下图:

在使用这个结构的时候,一般是将1个核作为生产者,向这个ring队列里面添加数据;另一个core或者多个core 作为消费者从这个ring队列中获取数据。生产者核访问上面的prod结构,消费者访问cons结构。

Ring支持的效果:

  • 先进先出
  • 最大大小是固定的,指针存储在表中
  • 无锁实现
  • 多消费者或单消费者出队
  • 多生产者或单生产者入队
struct rte_ring {                                                                                                                            
     /* Ring producer status. */                                                                                
     struct prod {                                                                                                
         uint32_t watermark;     /**< Maximum itemsbefore EDQUOT. */                                             
         uint32_t sp_enqueue;    /**< True, if single producer. */                                                
         uint32_t size;          /**< Size of ring.*/                                                           
         uint32_t mask;          /**< Mask (size-1)of ring. */                                                   
         volatile uint32_thead;  /**< Producer head.*/                                                           
         volatileuint32_t tail;  /**< Producer tail.*/                                                           
     } prod __rte_cache_aligned;                                                 
     /* Ring consumer status. */                                                                                
     struct cons {                                                                                                
         uint32_t sc_dequeue;    /**< True, if single consumer. */                                                
         uint32_t size;          /**< Size of thering. */                                                       
         uint32_t mask;          /**< Mask (size-1)of ring. */                                                   
         volatileuint32_t head;  /**< Consumer head.*/                                                           
         volatileuint32_t tail;  /**< Consumer tail.*/                                                                                                                                      
     } cons __rte_cache_aligned;                                                                                  
    void*ring[] __rte_cache_aligned;  
 };

2. Ring实现

2.1 单一生产者入队

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

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

第二步是修改环结构中的ring-> prod_head以指向与prod_next相同的位置。
指向添加对象的指针将复制到环(obj4)中。

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

2.2 单一消费者出队

同上

2.3 多个生产者入队

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

如果环中没有足够的空间(通过检查cons_tail 与 prod_head 差值可以检测到)

第二步是修改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上完成。

2.4 多个消费者出队

同上

3 总结

3.1 入队列

  1. 抢先更新头指针,此时头指针被更新为下一次入队列的起始位置,此时另外一个进程也是可以同时入队列的,只是要排队修改尾指针
  2. 然后放入数据
  3. 然后更新尾指针,其他进程排队更新尾指针

3.2 出队列

  1. 抢先更新头指针,此时头指针被更新为下一次出队列的起始位置,此时另外一个进程也是可以同时出队列的,只是要排队修改尾指针
  2. 然后取出数据
  3. 然后更新尾指针,其他进程排队更新尾指针

参考:https://blog.csdn.net/gengzhikui1992/article/details/108202876

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值