2014-01-07 4 views

ответ

3

вдумайтесь с плавающей точкой атомарных Давайте, от OS/аппаратной точки зрения дизайна ...

Atomics существуют потому, что они необходимы для синхронизации. Что включает в себя большинство синхронизации? Ручки, флаги, мьютексы, шпиндельные блоки - вещи, фактическое значение которых бессмысленно, если оно согласовано на пользователя и отличается между пользователями. Даже для чего-то вроде семафора, где значение более значимо - все равно около , подсчитывая, а не , измеряя, так что 32 бита стоят 32 бита, что бы мы его не представляли.

Во-вторых, технические проблемы. Практически все, что мы можем запрограммировать, выполняет целые операции. Не так плавающая точка - когда операции FP эмулируются библиотекой C, эти атомы будут сложными и невозможными для реализации. Даже в оборудовании операции FP обычно будут медленнее, чем целые, и кто хочет медленные блокировки? Конструкция самого FPU может даже затруднить реализацию атомных операций - например, если он висит от интерфейса сопроцессора без прямого доступа к шине памяти.

Вторично, если мы хотим float, конечно же, мы хотим double? Но у double часто возникает проблема быть больше, чем машинное слово, исключая атомарность четных нагрузок и хранилищ на многих архитектурах.

В-третьих, когда дело доходит до таких вещей, как атомисты, архитекторы ЦП стремятся реализовать то, что требуют системные дизайнеры и люди ОС, а люди ОС не любят с плавающей точкой вообще - глупые дополнительные регистры для сохранения, замедления контекста коммутаторы ... Дополнительные инструкции/функции в отношении стоимости и сложности аппаратного обеспечения, а также того, что клиенты не хотят их ...

Итак, короче говоря, этого недостаточно, поэтому нет поддержки оборудования , поэтому языковая поддержка отсутствует. Конечно, на некоторых архитектурах вы можете roll your own atomics, и я полагаю, что для вычисления графического процессора может потребоваться больше времени для синхронизации на оборудовании с плавающей запятой, поэтому кто знает, останется ли он таким?

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), соответствует инструкциям архитектуры ЦП, которые гарантируют эту атомарность (подробнее см. https://stackoverflow.com/a/1762179/1094941). Что касается того, почему нет поддержки сборки для поплавков, я не знаю.

+0

OpenCL предлагает атомарные операции с плавающей точкой с одинарной точностью. Он поддерживает несколько меньший поднабор C. http://www.khronos.org/ Он предназначен для портативных, AFAIK. –

1

Чтобы улучшить предыдущие ответы в контексте Go, мы можем использовать https://golang.org/pkg/math/#Float64bits и https://golang.org/pkg/math/#Float64frombits для преобразования float64s в и из uint64 без прямого использования небезопасного пакета.

Учитывая 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 
     } 
    } 
} 
+1

Этот ответ неверен. Вы можете попробовать '' ' вар х AtomicFloat64 x.Add (1) x.Add (1) x.Add (1) x.Value() -> -0,25, конечно, не 3 ' '' Если вам нужен лучший способ, ознакомьтесь с этим кодом: https://github.com/prometheus/client_golang/blob/master/prometheus/value.go#L91 – zviadm

+0

Вы абсолютно правы! У этого кода есть ошибка. Спасибо, что заметили, я обновлю ответ. –

+0

Не нужно делать 'a: = atomic.LoadUint64', потому что он может измениться перед следующим оператором' if'. См. Https://golang.org/src/sync/atomic/64bit_arm.go?s=508:615#L27 – gobwas

Смежные вопросы