有时候,就是想窥视一下不知道的东东,因为好奇!
分类: LINUX
2011-02-10 18:49:00
1.面临的问题:
一些汇编语言指令具有读"-修改-写"类型,即访问存储器单元时,先读原值,再写新值。在多个CPU上的多个内核控制路径同时“读-修改-写”同一个单元时,会造成受访数据的混乱。
如:两个CPU都访问同一单元,但是存储器仲裁器只允许其中的一个访问而让另一个延迟。当第一个读操作已经完成后,延迟的CPU从那个存储单元正好读到同一个旧值。然后,两个CPU都试图向那个存储器写新值,总线存储器访问再一次被存储仲裁器串行化,最终,两个写操作都成功。显然,从全局来看,结果是不对的。因为访问后的存储器的值,很可能只是后写入的内核控制路径写入的值。
2.问题的一个解决方式:
为避免上面"-修改-写"指令引起的竟争条件, 一个办法就是,确保这样的操作在工芯片级是原子的。任何一个这样的操作都以单个指令执行,中间不能中断,且避免其他的CPU访问同一个存储单元。
3.Linux内核中提供的的解决方式:
在编写c代码程序时,并不能保证编译器会为a=a+1或a++这样的操作使用一个原子指令。Linux内核提供了一个专门的atomic_t类型和一些专门的函数和宏,作用于atomic_t类型的变量,并当作单独的,原子的汇编语言指令来使用。
4.linux中的原子操作函数
atomic_read(v) 返回*v
atomic_set(v, i) 把*置成i
atomic_add(i, v) 把i加到*v
atomic_add_return(i, v) 把i加到*v, 返回*v的新值
atomic_add_negative(i, v) 把i加到*v, 若结果为负,则返回1,否则返回0
atomic_sub(i, v) 从中*v减去i
atomic_sub_return(v) 从中*v减去i, 返回*v的新值
atomic_sub_and_test(i, v) 从中*v减去i, 如果结果为0,返回1,否则返回0
atomic_inc(v) *v值加1
atomic_inc_and_test(v) *v值加1, 如果结果为0,返回1,否则返回0
atomic_inc_return(v) *v值加1,返回*v新值
atomic_dec(v) *v值减1
atomic_dec_and_test(v) *v值减1,如果结果为0,返回1,否则返回0
atomic_dec_return(v) *v值减1,返回*v新值
linux中的原子位处理函数
test_bit(nr, addr) 返回*addr的第nr位的值
set_bit(nr, addr) 设置*addr的第nr位
clear_bit(nr, addr) 清除*addr的第nr位
change_bit(nr, addr) 转换*addr的第nr位
test_and_set_bit(nr, addr) 设置*addr的第nr位, 并返回它的原值
test_and_clear_bit(nr, addr) 清除*addr的第nr位, 并返回它的原值
test_and_change_bit(nr, addr) 转换*addr的第nr位, 并返回它的原值
atomic_clear_mask(mask, addr) 清除mask指定的*addr的所有位
atomic_set_mask(mask, addr) 设置mask指定的*addr的所有位