layout | title | category | description | tags |
---|---|---|---|---|
post |
优化和内存屏障 |
内核同步 |
优化和内存屏障... |
内存屏障 |
当使用优化的编译器时,我们的指令有时候并不会严格按照它们再源代码中出现的顺序执行,因为编译器可能重新安排汇编语言指令以另寄存器以最优化的方式使用。此外,现代的CPU通常并行地执行若干条指令,且可能重新安排内存访问,这种重新安排可以极大地加速程序的执行。
当然,当处理器同步时,必须避免指令的重新排序,如果放在同步语句之后的一条指令再同步语句本身执行之前,就会出现失控,事实上,所有的同步原语起优化和内存屏障的作用。
优化屏障(optimization barrier)保证编译程序不会混淆放在原语操作之前的汇编语言指令和放在原语操作之后的汇编语言指令,这些汇编语言指令在C中都有对应的语句。再Linux中,优化屏障就是barrier()宏,它展开为asm volatile("":::"memory")。指令asm高速编译程序要插入汇编语言的片段。volatile关键字禁止编译器把asm指令与程序中的其他指令重新组合排序。memory关键字强制编译器假定RAM中的所有内存单元已经被汇编语言指令修改,因此,编译器不能使用存放在CPU寄存器中的内存单元的值来优化asm指令前的代码。不过值得注意的是,优化屏障并不保证不使当前的CPU把汇编语言指令混在一起执行。
内存屏障(memory barrier)确保,再此之后的操作开始执行之前,操作已经完成,因此,内存屏障类似于防火墙,可以让任何汇编语言指令都无法通过。再80x86处理器中,下列种类的汇编语言指令是『串行的』,因为它们起内存屏障的作用:
- 对I/O端口进行操作的所有指令。
- 有lock前缀的所有指令。
- 写控制寄存器、系统寄存器或调试寄存器的所有指令。
- 一些特别的汇编语言指令例如lfence、sfence和mfence等等。
- 少数专门的汇编语言指令,例如终止中断处理程序或异常处理程序的iret指令。
Linux使用六个内存屏障原语,这些原语也被当作优化屏障,因为我们必须保证编译程序不在屏障前后移动汇编语言指令。『读内存屏障』仅仅作用域从内村读指令,而『写内存品质』仅仅作用域写内存的指令。
内存屏障既用于多处理器系统也同样适用于单处理器系统,当内存屏障应该防止仅出现于多处理器系统上的竞争条件时,就使用smp_xxx(),在单处理器系统上,它们什么也不做,其他的内存屏障防止出现再单处理器和多处理器系统上的竞争条件。
这些内存屏障包括:
宏 | 说明 |
---|---|
mb() | 适用于MP和UP的内存屏障 |
rmb() | 适用于MP和UP的读内存屏障 |
wmb() | 适用于MP和UP的写内存屏障 |
smp_mb() | 仅适用于MP的内存屏障 |
smp_rmb() | 仅适用于MP的读内存屏障 |
smp_wmb() | 仅适用于MP的写内存屏障 |