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