После this link, я пытаюсь понять операционную коду ядра (есть 2 версии этого ядра кода, один с volatile local float *source
и другая с volatile global float *source
, т.е. local
и global
версии). Ниже я взять local
версию:Понимание метода для снижения OpenCL на поплавке
float sum=0;
void atomic_add_local(volatile local float *source, const float operand) {
union {
unsigned int intVal;
float floatVal;
} newVal;
union {
unsigned int intVal;
float floatVal;
} prevVal;
do {
prevVal.floatVal = *source;
newVal.floatVal = prevVal.floatVal + operand;
} while (atomic_cmpxchg((volatile local unsigned int *)source, prevVal.intVal, newVal.intVal) != prevVal.intVal);
}
Если я хорошо понимаю, каждая работа, пункт разделяет доступ к source
переменной благодаря классификатором «volatile
», не так ли?
Впоследствии, если я возьму рабочий элемент, код добавит operand
значение в newVal.floatVal
переменной. Затем после этой операции я вызываю функцию atomic_cmpxchg
, которая проверяет, выполнено ли предыдущее назначение (preVal.floatVal = *source;
и newVal.floatVal = prevVal.floatVal + operand;
), то есть путем сравнения значения, хранящегося по адресу source
, с preVal.intVal
.
В течение этого атомарных операций (которая не Бесперебойный по определению), так как значение, которое хранится в source
отличается от prevVal.intVal
, нового значение, которое хранится в source
является newVal.intVal
, которая на самом деле с плавающей точкой (потому что он кодируется на 4 байте, как целое число).
Можно ли сказать, что каждый рабочий элемент имеет доступ к мьютексу (я имею в виду заблокированный доступ) к значению, расположенному по адресу source address
.
Но для each work-item
нить, есть ли только одна итерация в while loop
?
Я думаю, что будет одна итерация, потому что сравнение «*source== prevVal.int ? newVal.intVal : newVal.intVal
» всегда присваивает значение newVal.intVal
значение, хранящееся в source address
, не так ли?
Любая помощь приветствуется, потому что я не понял все тонкости этого трюка для этого кода ядра.
UPDATE 1:
К сожалению, я почти понимаю все subtilities, особенно в while loop
: Первый случай
: для данного одного потока, перед вызовом atomic_cmpxchg, если prevVal.floatVal
по-прежнему равна *source
, тогда atomic_cmpxchg
изменит значение, содержащееся в указателе source
, и вернет значение, содержащееся в old pointer
, которое равно prevVal.intVal
, поэтому мы прерываем с while loop
.
Второй случай: Если между prevVal.floatVal = *source;
инструкцией и зову atomic_cmpxchg
, значение *source
изменилось (в другом потоке ??), то atomic_cmpxchg возвращает old
значение, которое больше не равна prevVal.floatVal
, поэтому условие в while loop
это правда, и мы остаемся в этом цикле до тех пор, пока предыдущее условие больше не будет проверено.
Мое понимание верно?
Благодаря
Извините, если это очевидно для вас (я думаю, что я еще не полностью понял вопрос), но ... цикл while является стандартным способом достижения атомарности, как и https: //en.wikipedia. org/wiki/Compare-and-swap – Marco13
Это классический цикл обмена обменом, упомянутый Марко. Игнорируйте профсоюзные трюки для ясности, они просто здесь, чтобы набирать текст. Кроме того, если у вас есть OpenCL 2+, встроенные атомы для поплавков. –
: Marco13,: Aldwin ok, спасибо. Давайте рассмотрим простой случай с двумя потоками. Если первый из них находится в цикле while, то до тех пор, пока второй не изменит значение «prevVal.floatVal», цикл while длится для первого потока, не так ли? Но в этом случае операция инкремента «prevVal.floatVal + операнд»; бесконечно (пока второй поток не остановит его), и поэтому значение, хранящееся в адресе «источник», очень велико, потому что я суммируюсь с очень большим количеством значений «операнда».С уважением – youpilat13