Здесь есть два очень разных поведения, MemoryBarrier()
и Barrier()
. У них обоих есть барьер в названии, но на самом деле они имеют совершенно разные эффекты.
Барьеры памяти предназначены для обеспечения некоторого относительного упорядочения памяти в пределах одного потока выполнения (например, одного вычислительного рабочего элемента). Доступ к памяти до того, как барьер должен быть завершен, до того, как доступ к барьеру будет разрешен. В традиционном коде ЦП это полезно для таких вещей, как блокировки - например, убедитесь, что замок успешно снят и записан в память, прежде чем касаться структуры, которую он защищал. На выполнение потоков внутри подгруппы относительно друг друга не влияют, так что вы можете запускать вещи параллельно, не истощая канал, и один поток в подгруппе может запускать код до барьера памяти, а другой - после кода барьер памяти.
Полные барьеры предназначены для выравнивания исполнения в подгруппе. Ни один поток в подгруппе не может запустить какой-либо код после барьера, пока все потоки не достигнут барьера, что неявно означает, что они также обеспечивают семантику барьера памяти. Это то, что вам нужно, когда вы хотите положиться на алгоритмы без блокировки, когда одному потоку нужно делать предположения о том, куда достиг другой поток в подгруппе. Например, ожидание потока для localInvocation 0 для заполнения локальной памяти.