Чтобы попытаться выразить это более четко (надеюсь),
mem_fence()
ждет, пока все операции чтения / записи в локальную и / или глобальную память, сделанные вызывающим рабочим элементом, будут выполнены до mem_fence () видны всем потокам в рабочей группе.
Это происходит из: http://developer.download.nvidia.com/presentations/2009/SIGGRAPH/asia/3_OpenCL_Programming.pdf
Операции с памятью могут быть переупорядочены в соответствии с устройством, на котором они работают.Спецификация утверждает (в основном), что любое переупорядочение операций с памятью должно гарантировать, что память находится в согласованном состоянии в пределах одного рабочего элемента.Однако что, если вы (например) выполняете операцию сохранения, и значение решает жить в кеше, относящемся к конкретному рабочему элементу, пока не наступит лучшее время для записи в локальную / глобальную память?Если вы попытаетесь загрузить из этой памяти, рабочий элемент, который записал значение, поместит его в кэш, так что никаких проблемНо другие рабочие элементы в рабочей группе этого не делают, поэтому они могут прочитать неправильное значение.Установка ограничителя памяти гарантирует, что во время вызова ограничителя памяти локальная / глобальная память (согласно параметрам) будет сделана согласованной (все кэши будут очищены, и любое переупорядочение будет учитывать то, что вы ожидаете, что другие потоки могутмне нужно получить доступ к этим данным после этого момента).
Я признаю, что это все еще сбивает с толку, и я не буду клясться, что мое понимание на 100% верно, но я думаю, что это по крайней мере общая идея.
Follow Up:
Я нашел эту ссылку, которая говорит о заборах памяти CUDA, но та же общая идея применима к OpenCL:
http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/NVIDIA_CUDA_Programming_Guide_2.3.pdf
Извлечение раздела B.5 Функции забора памяти .
У них есть пример кода, который вычисляет сумму массива чисел за один вызов.Код настроен для вычисления частичной суммы в каждой рабочей группе.Затем, если требуется выполнить суммирование, код должен выполнить последнюю рабочую группу.
Итак, в каждой рабочей группе в основном делается 2 вещи: частичная сумма, которая обновляет глобальную переменную., затем атомарное приращение глобальной переменной счетчика.
После этого, если осталось выполнить еще какую-либо работу, рабочая группа, увеличившая счетчик до значения («размер рабочей группы» - 1) считается последней рабочей группой.Эта рабочая группа продолжает завершать.
Теперь проблема (как они это объясняют) состоит в том, что из-за переупорядочения памяти и / или кэширования счетчик может увеличиваться, а последняя работа -Группа может начать выполнять свою работу до того, как глобальная переменная с частичной суммой получит свое последнее значение, записанное в глобальную память.
Ограничение памяти обеспечит согласованность значения этой переменной с частичной суммой для всех потоков перед перемещением.мимо забора.
Надеюсь, в этом есть какой-то смысл.Это сбивает с толку.