你的位置:电感厂 > 基础知识功率电感

透过 Linux 内核看无锁编程

2015-10-09 20:05:21      点击次数:
上一篇:Yaffs2文件系统中对NAND Flash磨损均衡的改进 贴片电感

清单 7. 2.4.34 RCU 实现代码

其中 ipc_lock 是读者,grow_ary 是写者,不论是读或者写,都需要加 spin lock 对被保护的数据结构进行访问。改变数组大小是小概率事件,而读取是大概率事件,同时被保护的数据结构是指针,满足 RCU 运用场景。以下代码摘自 2.6.10 内核:

清单 8. 2.6.10 RCU 实现代码

#define rcu_read_lock() preempt_disable()

#define rcu_read_unlock() preempt_enable()

#define rcu_assign_pointer(p, v) ({

smp_wmb();

(p) = (v);

})

struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)

{

……

rcu_read_lock();

entries = rcu_dereference(ids->entries);

if(lid >= entries->size) {

rcu_read_unlock();

return NULL;

}

out = entries->p[lid];

if(out == NULL) {

rcu_read_unlock();

return NULL;

}

……

return out;

}

static int grow_ary(struct ipc_ids* ids, int newsize)

{

struct ipc_id_ary* new;

struct ipc_id_ary* old;

……

new = ipc_rcu_alloc(sizeof(struct kern_ipc_perm *)*newsize +

sizeof(struct ipc_id_ary));

if(new == NULL)

return size;

new->size = newsize;

memcpy(new->p, ids->entries->p, sizeof(struct kern_ipc_perm *)*size

+sizeof(struct ipc_id_ary));

for(i=size;i new->p[i] = NULL;

}

old = ids->entries;

/*

* Use rcu_assign_pointer() to make sure the memcpyed contents

* of the new array are visible before the new array becomes visible.

*/

rcu_assign_pointer(ids->entries, new);

ipc_rcu_putref(old);

return newsize;

}

纵观整个流程,写者除内核屏障外,几乎没有一把锁。当写者需要更新数据结构时,首先复制该数据结构,申请 new 内存,然后对副本进行修改,调用 memcpy 将原数组的内容拷贝到 new 中,同时对扩大的那部分赋新值,修改完毕后,写者调用 rcu_assign_pointer 修改相关数据结构的指针,使之指向被修改后的新副本,整个写操作一气呵成,其中修改指针值的操作属于原子操作。在数据结构被写者修改后,需要调用内存屏障 smp_wmb,让其他 CPU 知晓已更新的指针值,否则会导致 SMP 环境下的 bug。当所有潜在的读者都执行完成后,调用 call_rcu 释放旧副本。同 Spin lock 一样,RCU 同步技术主要适用于 SMP 环境。

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

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

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

如图所示,当读者和写者指针相等时,表明缓冲区是空的,而只要写入指针在读取指针后面时,表明缓冲区已满。

清单 9. 2.6.10 环形缓冲区实现代码

/*

* __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 */

大电流电感
  • FPGA 技术在视频处理领域的应用 视频处理综述视频处理是目前多媒体领域最热门的技术,主要分为视频编解码和目标信息识别两大类。前者为了节省视频数据的传输带宽,主要依靠传统的信息论理论,目前已经比较成熟;后者则为了提取用户信息,是了人工

  • 基于DSP通讯全桥开关电源的研究与设计 摘要:针对传统开关电源中损耗较大,超调量较大,动态性能较差等问题,提出了基于DSP的全桥软开关技术。通过Matlab仿真结果表明模糊自适应PID控制算法比传统PID控制算法在超调量

  • 电感和电感线圈的原理电感是电子电路阻止电流改变的一种性质。注意“改变”一词的物理意义,这点非常重要,有点像力学中的惯性。一个电感线圈被用在磁场中储存能量,你会发现这个现象非常重要。为了理

  • 请教如何粗略计算纽扣电池供电使用时间
  • 保持电源/负载电路组合稳定的推荐方案序列
  • 飞兆半导体集成式智能功率级模块具有更高的功率
  • uc3842问题请教
  • 英飞凌F3系列IC设计小功率辅助电源图文详述
  • 家庭自动化无线通信解决方案
  • 一种线型组网的三线制数据测量方法
  • [DCDC]OC2004开关降压型DC-DC,GPS,电动车,电源类
  • 汽车自动变速器电控单元设计
  • 一种多路输出隔离驱动电路及其在短路限流器中的