最近看C++11 atomic发现对memory_order很是不理解,memory_order_relaxed/memory_order_consume/memory_order_acquire/memory_order_release/memory_order_acq_rel/
memory_order_seq_cst。这些都是跟memory model有关
关于memory model,对于线程来说,其实是跟编译器相关的。因为我们的编译器在把C++语言翻译成机器代码的时候,会进行各种优化。
我们做C++ GDB的时候,我们会发现,当我们使用-O2优化后,我们再调试的时候,发现程序的执行顺序根本就不是我们写的时候,我们想象的执行顺序。这样优化是有好处的,可以大大提高我们程序的运行速度,但是这样也不是都是好的(volatile类型不建议使用的原因,就是跟这个有关),这些优化都是建立在一个线程上进行的。所以在多线程的时候就要考虑优化造成的问题。
为了不让编译器在做优化的时候,不因为编译器的优化错误,而使程序错误,这就需要acquire/release原语。。
release时,编译器保证不会把写操作移到它后边,否则其他线程就看不到这个修改了;
acquire时,不会把其后的读操作移到它前面,否则读到的就是旧数据。
剩下的情况,编译器就可以自由移动读写操作
而在C++11
memory_order_acquire
Acquire operation:
no reads in the current thread can be reordered before this load.
This ensures that all writes in other threads that release the same atomic variable are visible in the current thread
Acquire 操作:
在当前线程中,所有的read操作的乱序,不能出现在这个atomic变量load之前。(意思就是在当前线程中,编译器或者cpu在优化代码的时候,
不能把读操作的代码出现在这个变量之前)
这保证所有的write在当前线程中是可以得到的,当然前提是在其他线程中共用这个atomic的变量的,应该释放这个atmic变量(意思就是:保证
所有的写操作都是有效的,防止在优化后,出现“已经读完了,但是还没写”的情况出现。)
memory_order_release:
Release operation:
no writes in the current thread can be reordered after this store.
This ensures that all writes in the current thread are visible in other threads that acquire the same atomic variable.
memory_order_relaxed: 说明这个操作除了是原子的外,周围的操作随便移动,比较适合做计数器
memory_order_acq_rel基本是memory_order_acquire和memory_order_release的合体
memory_order_scq_cst是memory_order_acq_rel的加强版, atomic默认是这个
memory_order_consume是memory_order_acquire的弱化版,它只保证不把跟当前load的变量有依赖的变量reorder,没依赖关系的随便移动
参考资料:
3. Why the "volatile" type class should not be used