0%

线程同步与原子操作

volatile

  • volatile使得代码每次在读写volatile变量时都需要从内存读写,而不能使用寄存器中缓存的值。并且也禁止编译器对volatible做编译优化。volatile本身并不是用于线程同步,也不保证原子读写(例如volatile a++这种需要几个指令才能完成的操作)。volatile主要用于access to memory mapped devices和variables in signal handlers and between setjmp and longjmp。C++标准禁止编译器reorder同一个线程内的volatile变量的读写,但不同线程则没有限制。non-volatile变量则有可能发生reorder(Stay away from Volatile in threaded code?)。而根据为什么volatile++不是原子性的?中的说法,volatile的读操作后会插入LoadLoad和LoadStore屏障,避免volatile读操作与后面的普通读写发生reorder。而volatile的写操作前会插入StoreLoad和StoreStore屏障,避免volatile写操作与后面的普通读写发生reorder。
  • volatile跟const一样属于变量修饰符,因此也和const一样必须弄清楚修饰的是指针还是变量自身(或者甚至是第几级指针)。例如uchar * volatile reg;说明指针reg本身是volatile的,而volatile uchar *reg;说明*reg(也就是reg指向的变量)是volatile的。而且volatile也可以和const同时使用。
  • volatile陷阱一文中有提到几种volatile的陷阱和误用。
  • “Volatile” can be harmful…中提到可以将函数参数标记为volatile避免编译器优化,从而便于debug。

临界区块(Critical section)

内存屏障

  • 首先要明白的一点,reorder不仅可以发生在编译时,也可以发生在运行时。CPU流水线也可以重排某些指令顺序。所以即使是同一段编译好的程序,不同的CPU内核也可能执行不同的指令顺序。

本文地址:http://xnerv.wang/thread-synchronization-and-atomic-operation/