理解 Memory barrier(内存屏障)【转】 (5)

这里内存操作有序。然而在 Alpha CPU 上,存在依赖的内存读取操作不一定有序,需要使用数据依赖 barrier(由于 Alpha 不常见,这里就不详细解释了)。

在 Linux 内核中,除了前面说到的编译器 barrier — barrier() 和 ACCESS_ONCE(),还有 CPU Memory barrier:

通用 barrier,保证读写操作有序的,mb() 和 smp_mb()

写操作 barrier,仅保证写操作有序的,wmb() 和 smp_wmb()

读操作 barrier,仅保证读操作有序的,rmb() 和 smp_rmb()

注意,所有的 CPU Memory barrier(除了数据依赖 barrier 之外)都隐含了编译器 barrier。这里的 smp 开头的 Memory barrier 会根据配置在单处理器上直接使用编译器 barrier,而在 SMP 上才使用 CPU Memory barrier(也就是 mb()、wmb()、rmb(),回忆上面相关内核代码)。

最后需要注意一点的是,CPU Memory barrier 中某些类型的 Memory barrier 需要成对使用,否则会出错,详细来说就是:一个写操作 barrier 需要和读操作(或数据依赖)barrier 一起使用(当然,通用 barrier 也是可以的),反之依然。

Memory barrier 的范例

读内核代码进一步学习 Memory barrier 的使用。
Linux 内核实现的无锁(只有一个读线程和一个写线程时)环形缓冲区 kfifo 就使用到了 Memory barrier,实现源码如下:

/*

* A simple kernel FIFO implementation.

*

* Copyright (C) 2004 Stelian Pop <stelian@popies.net>

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

* This program is distributed in the hope that it will be useful,

* but WITHOUT ANY WARRANTY; without even the implied warranty of

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

* GNU General Public License for more details.

*

* You should have received a copy of the GNU General Public License

* along with this program; if not, write to the Free Software

* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*

*/

 

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/slab.h>

#include <linux/err.h>

#include <linux/kfifo.h>

#include <linux/log2.h>

 

/**

* kfifo_init - allocates a new FIFO using a preallocated buffer

* @buffer: the preallocated buffer to be used.

* @size: the size of the internal buffer, this have to be a power of 2.

* @gfp_mask: get_free_pages mask, passed to kmalloc()

* @lock: the lock to be used to protect the fifo buffer

*

* Do NOT pass the kfifo to kfifo_free() after use! Simply free the

* &struct kfifo with kfree().

*/

struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,

gfp_t gfp_mask, spinlock_t *lock)

{

struct kfifo *fifo;

 

/* size must be a power of 2 */

BUG_ON(!is_power_of_2(size));

 

fifo = kmalloc(sizeof(struct kfifo), gfp_mask);

if (!fifo)

return ERR_PTR(-ENOMEM);

 

fifo->buffer = buffer;

fifo->size = size;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzsdzs.html