![Rank: 8](images/default/star_level3.gif) ![Rank: 8](images/default/star_level3.gif)
- UID
- 872238
|
![](http://images.eccn.com/silabs/silicon_chip_980x60_202203.jpg)
环形缓冲区是生产者和消费者模型中常用的数据结构。生产者将数据放入数组的尾端,而消费者从数组的另一端移走数据,当达到数组的尾部时,生产者绕回到数组的头部。
如果只有一个生产者和一个消费者,那么就可以做到免锁访问环形缓冲区(RingBuffer)。写入索引只允许生产者访问并修改,只要写入者在更新索引之前将新的值保存到缓冲区中,则读者将始终看到一致的数据结构。同理,读取索引也只允许消费者访问并修改。
![](http://embed.chinaitlab.com/UploadFiles_4615/201206/20120609035315178.jpg)
图2。环形缓冲区实现原理图
如图所示,当读者和写者指针相等时,表明缓冲区是空的,而只要写入指针在读取指针后面时,表明缓冲区已满。
清单9。2。6。10环形缓冲区实现代码
/*
*__kfifo_put-putssomedataintotheFIFO,nolockingversion
*Notethatwithonlyoneconcurrentreaderandoneconcurrent
*writer,youdon'tneedextralockingtousethesefunctions。
*/
unsignedint__kfifo_put(structkfifo*fifo,
unsignedchar*buffer,unsignedintlen)
{
unsignedintl;
len=min(len,fifo->size-fifo->in+fifo->out);
/*firstputthedatastartingfromfifo->intobufferend*/
l=min(len,fifo->size-(fifo->in&(fifo->size-1)));
memcpy(fifo->buffer+(fifo->in&(fifo->size-1)),buffer,l);
/*thenputtherest(ifany)atthebeginningofthebuffer*/
memcpy(fifo->buffer,buffer+l,len-l);
fifo->in+=len;
returnlen;
}
/*
*__kfifo_get-getssomedatafromtheFIFO,nolockingversion
*Notethatwithonlyoneconcurrentreaderandoneconcurrent
*writer,youdon'tneedextralockingtousethesefunctions。
*/
unsignedint__kfifo_get(structkfifo*fifo,
unsignedchar*buffer,unsignedintlen)
{
unsignedintl;
len=min(len,fifo->in-fifo->out);
/*firstgetthedatafromfifo->outuntiltheendofthebuffer*/
l=min(len,fifo->size-(fifo->out&(fifo->size-1)));
memcpy(buffer,fifo->buffer+(fifo->out&(fifo->size-1)),l);
/*thengettherest(ifany)fromthebeginningofthebuffer*/
memcpy(buffer+l,fifo->buffer,len-l);
fifo->out+=len;
returnlen;
}
以上代码摘自2。6。10内核,通过代码的注释(斜体部分)可以看出,当只有一个消费者和一个生产者时,可以不用添加任何额外的锁,就能达到对共享数据的访问。
总结
通过对比2。4和2。6内核代码,不得不佩服内核开发者的智慧,为了提高内核性能,一直不断的进行各种优化,并将业界最新的lock-free理念运用到内核中。
在实际开发过程中,进行无锁设计时,首先进行场景分析,因为每种无锁方案都有特定的应用场景,接着根据场景分析进行数据结构的初步设计,然后根据先前的分析结果进行并发模型建模,最后在调整数据结构的设计,以便达到最优。 |
|