leveldb(一):AtomicPointer
来源:互联网 发布:西南大学网络教育2017 编辑:程序博客网 时间:2024/06/16 00:29
AtomicPointer 简介
AtomicPointer 是 leveldb 提供的一个原子指针操作类,使用了基于内存屏障的同步访问机制,这比用锁和信号量的效率要高。
源文件位置:leveldb/port/atomic_pointer.h
它的实现主要分为两种:
(一)利用std::atomic实现AtomicPointer
std::atomic对int, char, bool等数据结构进行原子性封装,在多线程环境中,对std::atomic对象的访问不会造成竞争-冒险。利用std::atomic可实现数据结构的无锁设计。(对于std::atomic的详细分析可以参见我的c++11分类里的C++11开发中的Atomic原子操作)
class AtomicPointer { private: std::atomic<void*> rep_; public: AtomicPointer() { } explicit AtomicPointer(void* v) : rep_(v) { } // 使用内存屏障的读操作,即同步读 inline void* Acquire_Load() const { return rep_.load(std::memory_order_acquire); } // 使用内存屏障的读操作,即同步写 inline void Release_Store(void* v) { rep_.store(v, std::memory_order_release); } inline void* NoBarrier_Load() const { // 不使用内存屏障的读操作,即不同步的读操作 return rep_.load(std::memory_order_relaxed); } inline void NoBarrier_Store(void* v) { // 同上,是不同步的写操作 rep_.store(v, std::memory_order_relaxed); }};
(二)利用内存屏障来实现AtomicPointer
class AtomicPointer { private: void* rep_; public: AtomicPointer() { } explicit AtomicPointer(void* p) : rep_(p) {} // 不使用内存屏障的读操作,即不同步的读操作 inline void* NoBarrier_Load() const { return rep_; } // 同上,是不同步的写操作 inline void NoBarrier_Store(void* v) { rep_ = v; } // 使用内存屏障的读操作,即同步读 inline void* Acquire_Load() const { void* result = rep_; // 添加一个内存屏障,后面会有原理介绍 MemoryBarrier(); return result; } // 使用内存屏障的写操作,即同步写 inline void Release_Store(void* v) { MemoryBarrier(); rep_ = v; }};
// Define MemoryBarrier() if available// Windows on x86#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)// windows.h already provides a MemoryBarrier(void) macro#define LEVELDB_HAVE_MEMORY_BARRIER// Gcc on x86#elif defined(ARCH_CPU_X86_FAMILY) && defined(__GNUC__)inline void MemoryBarrier() { __asm__ __volatile__("" : : : "memory");}#define LEVELDB_HAVE_MEMORY_BARRIER#endif
从上面可以看出windows平台已经定义过MemoryBarrier(void)的宏,可以直接使用。
而linux平台的gcc则通过我们自己内联一条汇编来自定义MemoryBarrier。
asm volatile(“” : : : “memory”);
这里的volatile主要是用来防止编译器优化的。而这里的优化是针对代码块而言的,使用嵌入式汇编的代码分成三块:
1、嵌入式汇编之前的c代码块
2、嵌入式汇编代码块
3、嵌入式汇编之后的c代码块
这里volatile就是告诉编译器:不要因为性能优化而将这些代码重排,我需要清清爽爽的保持这三块代码块的顺序(代码块内部是否重排不是这里的volatile管辖范围了)。
MemoryBarrier是添加一个内存屏障的函数,当这个函数之前的代码修改了某个变量的内存值后,其他 CPU 和缓存 (Cache) 中的该变量的值将会失效,必须重新从内存中获取该变量的值。
总的来说,AtomicPointer 这个类是为了让我们以更高的效率实现原子性的访问。
什么是内存屏障 ?
内存屏障是同步的一种方法,类似于锁和信号量,但是它有更高的效率。内存屏障深入研究的水很深,这里只介绍它的基本用途和使用,而不会深入。(如果你想深入了解内存屏障,请看我的 内核之同步 分类里的 memory barrier)
基本用途
避免编译器优化指令
有些编译器默认会在编译期间对代码进行优化,从而改变汇编代码的指令执行顺序,如果你是在单线程上运行可能会正常,但是在多线程环境很可能会发生问题(如果你的程序对指令的执行顺序有严格的要求)。
而内存屏障就可以阻止编译器在编译期间优化我们的指令顺序,为你的程序在多线程环境下的正确运行提供了保障,但是不能阻止 CPU 在运行时重新排序指令。
如果你想实现下面这样的功能,那你可以考虑内存屏障:
修改一个内存中的变量之后,其余的 CPU 和 Cache 里面该变量的原始数据失效,必须从内存中重新获取这个变量的值。
这保证了这个变量对 CPU 和 Cache 是「可见的」,leveldb 就使用了这个特性
- leveldb(一):AtomicPointer
- LevelDB : AtomicPointer
- leveldb AtomicPointer
- LevelDB源码分析之四:AtomicPointer
- leveldb学习笔记一 SLICE
- LevelDb
- LevelDb
- LevelDb
- leveldb
- leveldb
- leveldb
- leveldb
- LevelDb
- LevelDb
- Leveldb
- Leveldb
- levelDB
- LevelDb
- 仿小米时钟-简约版
- js面向过程的选项卡
- 补6/27
- EditText不自动弹出键盘,界面退出隐藏键盘
- 【C/C++】链表的理解与使用
- leveldb(一):AtomicPointer
- Codeforces821B Okabe and Banana Trees
- placeholder兼容ie和password
- 用于正则表达式模式匹配的String方法
- 大家好,我是黑客H,我为M高校的网络安全带盐!
- 金山词霸每日一句
- java mongodb aggregate用法
- 关于sublime text3乱码问题
- 十五分钟介绍 Redis数据结构