KFIFO入门笔记

本文介绍了KFIFO无锁队列的基本逻辑流程,包括申请固定空间、入队与出队操作,强调了内存一致性顺序的重要性,并探讨了在不同场景下是否需要加锁或使用CAS操作。此外,还提到了无锁队列的其他实现方式,如RingBuffer、SPSC和Disruptor。文章详细讲解了涉及的CAS指令和内存屏障技术,并提供了KFIFO的C++11实现代码,同时分享了学习KFIFO的初衷——创建高性能的Linux C++日志模块库。

KFIFO入门笔记

一、 KFIFO的逻辑流程

  1. 申请一块固定空间,作为循环队列。
  2. 入队操作优先copy数据,然后下标in加一。
  3. 出队操作优先取出数据,然后下标out加一。
  4. 为保证内存一致性顺序,使用内存屏障保证下标加一操作在内存copy之后执行。
  5. 下标加一是否要加锁或使用CAS操作,根据具体情况而定,linux下测试uint32_t不用加锁,windows要加锁或使用CAS。
  • 注意以上操作仅适用于单生产者单消费者场景,多生产者,多消费者场景可以分别在两端加锁,使其模拟单生产者单消费者场景。
  • 保证无锁也能保证单消费者线程和单生产者线程操作数据正确的原理是:
  1. 首先保证下标in和out的操作的原子性(使用CAS函数等方式)
  2. 其次是最重要的,保证下标加一操作在内存操作之后执行,这个不仅仅是将内存操作代码写在下标移动代码之前就能实现的,因为程序在执行时,基于操作系统对于性能优化的考虑,会调整命令执行顺序,导致内存操作这种耗时大的命令,即使代码在下标移动命令之前,也会可能在下标移动命令之后执行,导致消费者线程读取下标后,但对应的内存还未拷贝完毕,从而导致数据操作错误,而内存屏障可以解决这个问题。详细的原理介绍,可以搜索缓存一致性

二、无锁队列的几种实现方式

  1. RingBuffer
  2. KFifo
  3. SPSC
  4. Disruptor

三、涉及的技术

  1. CAS指令
  2. 内存屏障

四、需要了解的知识

  1. 缓存一致性顺序

五、KFIFO实现代码

环境:linux , C++11

my_kifo.h

//
// Created by hapYP on 8/26/22.
// Implement a non-lock queue.
//

#ifndef MY_KFIFO_MY_KFIFO_H
#define MY_KFIFO_MY_KFIFO_H


#if 0
#include <stdint.h>
#include <pthread.h>


#define min(x, y)    ((x) < (y) ? (x) : (y))
#define smp_wmb()    __asm__ __volatile__("": : :"memory")

//typedef void* FifoElemType;
struct KFIFO {
    uint32_t in;
    uint32_t out;
    uint32_t mask;   // size - 1;
    uint32_t eSize;   // element size
    void *data;
};

/**
* @brief: Initialize a struct KFIFO.
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern int KFifoInit(struct KFIFO *_kfifo, uint32_t _size, uint32_t _eSize);

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern uint32_t KFifoInLock(struct KFIFO *_kFifo, const void *_buf, uint32_t _len, pthread_spinlock_t *_lock);

/**
* @brief: Copy the data started at _buf and length _len to _kFifo;
* @param:
* @retType: uint32_t
* @retVal: The length copy into kFifo successfully. less than or equal _len;
* @bug:
**/
extern uint32_t KFifoIn(struct KFIFO *_kFifo, const void *_buf, uint32_t _len);

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
static void KFifoCopyIn(struct KFIFO *_kFifo, const void *src, uint32_t _len, uint32_t _off);

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern uint32_t KFifoOut(struct KFIFO *_kFifo, void *_buf, uint32_t _wantCopyOutLen);

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
static void KFifoCopyOut(struct KFIFO *_kFifo, void *_buf, uint32_t _copyOutLen, uint32_t _off);


/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern uint32_t KFifoUnused(struct KFIFO *_kFifo);

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern int IsFifoEmpty();

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern int IsFifoFull();

/**
* @brief:
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern int KFifoDestroy();

/**
* @brief: Get the minimum of power 2 and greater than _value
* @param:
* @retType:
* @retVal:
* @bug:
**/
extern uint64_t MinUpPowerTwo(uint32_t _value);
#endif

#include <stdint.h>



#define Min(x, y) ((x) > (y) ? (y) : (x))
#define smp_wmb() __asm__ __volatile__("": : :"memory")

/*
 * Define the struct describes the KFifo.
 */
struct KFIFO{
    uint32_t in;  // push in
    uint32_t out;  // pop out
    uint32_t mask;  // total size - 1
    uint32_t elemSize;   // the size of element type
    void *pData;  // the first address of memory for saving the data.
};



/**
* @brief: Initialize struct KFIFO and alloc memory for KFIFO.pData.
* @param: _pKfifo: The start address of struct KFIFO.
* @param: _size: The total bytes of the KFIFO.pData wanting to alloc.
* @param: _elemSize: The bytes of element type.
* @ret: 0: success
* @ret: -1: fail
* @bug: None
**/
int KFifoInit(struct KFIFO *_pKFifo, uint32_t _size, uint32_t _elemSize);

/**
* @brief: Calculate the minimum which is greater than _num and is the power of two.
* @param: _num: number be calculated.
* @ret: Calculate result.
* @bug:
**/
uint64_t RoundupPowOfTwo(uint32_t _num);

/**
* @brief: Return the count of unused block.
* @param: _pKFifo:
* @ret:
* @bug:
**/
uint32_t KFifoUnused(struct KFIFO *_pKFifo);

int IsKFifoEmpty(struct KFIFO *_pKFifo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值