浮子上的原子操作

时间:2014-01-07 20:15:57

标签: c operating-system kernel atomic atomicity

大多数语言都提供原子int操作的功能(添加,比较和交换等)。

为什么不对浮动类型?

4 个答案:

答案 0 :(得分:5)

从操作系统/硬件设计的角度来看,让我们思考浮点原子......

存在原子,因为它们需要同步。大多数同步涉及什么?句柄,标志,互斥锁,自旋锁 - 只要每个用户一致且用户之间不同,其实际价值毫无意义的东西。即使像信号量这样的值更有意义的东西 - 它仍然是计算而不是测量,所以无论我们认为它代表什么,32位都值32位。 / p>

其次,技术问题。我们可以编程的任何东西都可以进行整数运算。不是那么浮点 - 当C操作由C库模拟时,那些原子将在困难和不可能实现之间。即使在硬件中,FP操作通常会比整数慢,谁想要慢速锁? FPU本身的设计甚至可能使实现原子操作变得困难 - 例如如果没有任何直接访问内存总线的情况下挂起协处理器接口。

第二个半,如果我们想要float,我们当然也需要double吗?但double通常存在比机器字更大的问题,排除了在许多架构上均匀加载和存储的原子性。

第三,当谈到像原子一样的东西时,CPU架构师倾向于实现系统设计人员和操作系统人员要求的东西,操作系统人员并不完全喜欢一般的浮点 - 愚蠢的额外寄存器来保存,减慢上下文切换...硬件中的更多指令/功能会降低功耗和复杂性,如果客户不需要它们......

因此,简而言之,用例不够用,因此没有硬件支持,因此没有语言支持。当然,在某些架构上你可以roll your own atomics,我认为GPU计算可能对主要浮点硬件的同步有更多的需求,所以谁知道它是否会保持这种状态?

答案 1 :(得分:1)

啊,最初的问题是用Go标记的,并且略有不同,所以这就是我要回答的问题,对不起,如果这不是编辑问题的完整答案:)

使用Go,您可以原子地交换任何指针值,并在不安全的黑暗面上进行一次小行程:

http://play.golang.org/p/aFbzUMhfEB

摘录:

var uptr unsafe.Pointer
var f1, f2 float64

f1 = 12.34
f2 = 56.78
// Original values
fmt.Println(f1, f2)
uptr = unsafe.Pointer(&f1)
atomic.SwapPointer(&uptr, unsafe.Pointer(&f2))
f1 = *(*float64)(unsafe.Pointer(uptr))
// f1 now holds the value of f2, f2 is untouched
fmt.Println(f1, f2)

交换调用(以及其他原子操作,如CAS)映射到CPU架构的指令,该指令保证了这种原子性(有关更多详细信息,请参阅https://stackoverflow.com/a/1762179/1094941)。至于为什么没有花车的装配支持,我不知道。

答案 2 :(得分:1)

为了改进Go上下文中的先前答案,我们可以使用https://golang.org/pkg/math/#Float64bitshttps://golang.org/pkg/math/#Float64frombits将float64s转换为uint64s,而不直接使用不安全的软件包。

鉴于uint64,我们可以使用所有可用的原子基元。

type AtomicFloat64 uint64

func (f *AtomicFloat64) Value() float64 {
    return math.Float64frombits(atomic.LoadUint64((*uint64)(f)))
}

func (f *AtomicFloat64) Add(n float64) float64 {
    for {
        a := atomic.LoadUint64((*uint64)(f))
        b := math.Float64bits(math.Float64frombits(a) + n)
        if atomic.CompareAndSwapUint64((*uint64)(f), a, b) {
            return
        }
    }
}

答案 3 :(得分:0)

CAS(比较和交换)是最重要的原子操作,因为可以用它来模拟其他(addandor等)。

我认为,浮点数不具有CAS功能的一个重要原因是,相等性不适用于IEEE754浮点数,其处理方式与整数类型不一样。例如,只要原来的期望值或实际值变成NaN,您就不会知道CAS交换是否成功。请记住,将NaN与包含NaN的任何其他值进行比较将始终返回false。

对于原子按位和算术运算,它们对浮点的用处远不如对整数有用。