内核无锁第四层级 — 免锁

环形缓冲区是生产者和消费者模型中常用的数据结构。生产者将数据放入数组的尾端,而消费者从数组的另一端移走数据,当达到数组的尾部时,生产者绕回到数组的头部。

如果只有一个生产者和一个消费者,那么就可以做到免锁访问环形缓冲区(Ring Buffer)。写入索引只允许生产者访问并修改,只要写入者在更新索引之前将新的值保存到缓冲区中,则读者将始终看到一致的数据结构。同理,读取索引也只允许消费者访问并修改。

图 2. 环形缓冲区实现原理图  

如图所示,当读者和写者指针相等时,表明缓冲区是空的,而只要写入指针比读取指针多fifo->size时,表明缓冲区已满。

kfifo的定义文件:kernel/kfifo.c

kfifo的头文件:  include/linux/kfifo.h

struct kfifo { 
    unsigned char *buffer;    /* the buffer holding the data */ 
    unsigned int size;    /* the size of the allocated buffer */ 
    unsigned int in;    /* data is added at offset (in % size) */ 
    unsigned int out;    /* data is extracted from off. (out % size) */ 
    spinlock_t *lock;    /* protects concurrent modifications */ 
};

 

/* 
 * __kfifo_put - puts some data into the FIFO, no locking version 
 * Note that with only one concurrent reader and one concurrent 
 * writer, you don't need extra locking to use these functions. 
 */ 
 unsigned int __kfifo_put(struct kfifo *fifo, 
       unsigned char *buffer, unsigned int len) 
 { 
  unsigned int l; 
  len = min(len, fifo->size - fifo->in + fifo->out); 
  /* first put the data starting from fifo->in to buffer end */ 
  l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); 
  memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); 
  /* then put the rest (if any) at the beginning of the buffer */ 
  memcpy(fifo->buffer, buffer + l, len - l); 
  fifo->in += len; 
  return len; 
 } 

 /* 
 * __kfifo_get - gets some data from the FIFO, no locking version 
 * Note that with only one concurrent reader and one concurrent 
 * writer, you don't need extra locking to use these functions. 
 */ 
 unsigned int __kfifo_get(struct kfifo *fifo, 
     unsigned char *buffer, unsigned int len) 
 { 
  unsigned int l; 
  len = min(len, fifo->in - fifo->out); 
  /* first get the data from fifo->out until the end of the buffer */ 
  l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); 
  memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); 
  /* then get the rest (if any) from the beginning of the buffer */ 
  memcpy(buffer + l, fifo->buffer, len - l); 
  fifo->out += len; 
  return len; 
 }

注意第12行,仅当fifo->size等于2^n时,fifo->in & (fifo->size - 1)等于fifo->in%fifo->size,否则出错。

以上代码摘自 2.6.10 内核,通过代码的注释(斜体部分)可以看出,当只有一个消费者和一个生产者时,可以不用添加任何额外的锁,就能达到对共享数据的访问。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值