atomic 内存序

mac2024-12-13  22

提高性能的一种方式  atomic 替换mutex

内存序跟原子操作本身并不冲突, 不论用那种内存序该原子还是原子操作

atomic内存序: 就是来指定顺序的

例子:

注 : 像类似 memory_order_relaxed 都是以函数为单位来重新排执行指令的 [这个注释后面再来看好了] #include <atomic> atomic<int> a (0); atomic<int> b(0); unsigned int __stdcall thread_write(void *ar){ int hahah = 123; //1 int balala = hahah; //2 a.store(1,std::memory_order_relaxed); //3 b.store(666,std::memory_order_relaxed); //4 bool ooo = false; //7 return 0; } unsigned int __stdcall thread_read(void * arg){ while(b.load(std::memory_order_relaxed) != 666); //5 int r = a.load(std::memory_order_relaxed); //6 cout << "a : " << r << endl; assert( r ==1 ); return 0; } int main(int argc, char* argv[]) { HANDLE t1 = (HANDLE)_beginthreadex(0,0,thread_read,0,0,0); HANDLE t2 = (HANDLE)_beginthreadex(0,0,thread_write,0,0,0); while(1){ Sleep(1000); } cout << "main done" << endl; return 0; } memory_order_relaxed 随意的顺序 , 怎么个意思呢?

thread_write 中 1,2 是固定的, 3,4,7可以随意,即 1,2, 3,4,7  / 1,2,4,3,7 / 7,4,3,1,2  等

thread_read 中 5,6 随意

因此,thread_read中的 6 在弱内存模型中【意思是把指令重排,提高并行能力 => 编译器干的】 不一定是 1 ,可以是0,或者1;

比如 thread_read 中 a.load 将先执行,  thread_write还没开始,则 a == 0;

那么如何保证写的顺序呢?    memory_order_release 

如果你熟悉多线程,那么可以这么理解:

lock() -> 做一些事 -> unlock() ->  (  ReleaseSemaphore 或者 sem_post) 

如果不熟悉多线程, 那么就从字面意思理解好了, release 相当于生成一个release 版本的程序, 即前面的该有的操作都完成了才 

能生成一个release 版本;

代码:  修改 thread_write

unsigned int __stdcall thread_write(void *ar){ int hahah = 123; //1 a.store(1,std::memory_order_relaxed); //2 //修改这里 b.store(666,std::memory_order_release); //3 return 0; }

 

memory_order_release 的意思是 1,2 随意,但不能放到我后面, 到我这,你们前面的该执行该完成都得搞完;

到此, thread_read 函数能够保证正确吗? 

unsigned int __stdcall thread_read(void * arg){ while(b.load(std::memory_order_relaxed) != 666); int r = a.load(std::memory_order_relaxed); assert( r ==1 ); return 0; }

很不幸, 不能!

memory_order_release 在thread_write 函数中保证了执行指令的顺序

thread_read 中并没有任何保证;   a.load 还是有可能被先执行;

相当于 :

1. a.load 

2. while( b.load() )

接下来就是轮到   memory_order_acquire 这个东西; 修改一行代码即可;

unsigned int __stdcall thread_read(void * arg){ while(b.load(std::memory_order_acquire) != 666); int r = a.load(std::memory_order_relaxed); assert( r ==1 ); return 0; }

意思是, 此处的指令 编译器你别给我乱动,就按这个顺序来.

如果熟悉mutex, 就把此处当 lock 即可;

 

最新回复(0)