---
title: Synchronizing passes with consumer barriers
framework: metal
role: article
role_heading: Article
path: metal/synchronizing-passes-with-consumer-barriers
---

# Synchronizing passes with consumer barriers

Block GPU stages in a pass, and all subsequent passes, from running until stages from earlier passes finish.

## Overview

Overview Consumer queue barriers are coarse synchronization primitives that resolve access conflicts between commands in different passes that you submit to the same command queue, including the passes from other command buffers you submit to the same queue. Consumer barriers are convenient for synchronizing passes that load from common resources that multiple, earlier passes modify in the same queue. note: You can also add consumer barriers with Metal 3 encoder types. When your app encodes commands that access a resource from different passes — or different stages within a single pass — it creates an access conflict when at least one command modifies that resource. This conflict happens because the GPU can run multiple commands at the same time, including those from: Multiple passes Different stages of a pass, such as the blit and dispatch stages of a compute pass Multiple instances of a stage, such as two or more dispatch commands within a compute pass For more information about resource access conflicts and GPU stages, see Resource synchronization and MTLStages, respectively. Start by identifying which memory operations from previous passes in the same queue introduce a conflict and resolve it with a consumer queue barrier in the consumer pass. tip: As an alternative for Metal 4 queues, create a single producer queue barrier in the producing pass that’s the equivalent of multiple consumer queue barriers for applicable scenarios. For more information, see Synchronizing passes with producer barriers. Identify access conflicts on the same queue The following code example encodes three compute passes. The first pass runs a single copy command: The second pass runs a copy command and a dispatch command: The third pass runs a single dispatch command: The example has at least one access conflict because passes 1 and 2 both access a common resource, bufferB: The copy command from the first pass stores to bufferB. The dispatch command from the second pass loads from bufferB.

Without synchronization, the GPU can run all three passes and their stages in parallel, which can yield inconsistent results in resources with access conflicts.

Resolve access conflicts with a consumer barrier Resolve access conflicts between passes from the same command queue with a consumer barrier by calling the encoder’s barrier(afterQueueStages:beforeStages:visibilityOptions:) method. Each consumer queue barrier temporarily blocks the GPU from running the specific stage types you pass to the beforeStages parameter in the current pass, and all subsequent passes in the same queue. The barrier unblocks those stages when all the stage types you pass to the afterQueueStages parameter finish running in all previous passes. important: The stages you pass to the beforeStages parameter of the barrier(afterQueueStages:beforeStages:visibilityOptions:) method apply to the pass you’re encoding and all subsequent passes, but the stages of the afterQueueStages parameter only apply to previous passes. The following example modifies the code that encodes the second pass by adding a consumer queue barrier just before the dispatch command stage in the second pass: In this example, the barrier prevents the GPU from running the dispatch stage in both the second and third passes until the blit stage in the first pass finishes storing its modifications.

The barrier unblocks both dispatch stages when the blit stage from the first pass finishes running because it’s the only pass that applies to the afterQueueStages parameter. For more information about other synchronization mechanisms, see these articles in the series: Synchronizing stages within a pass Synchronizing passes with a fence Synchronizing passes with producer barriers

## See Also

### Synchronizing with barriers and fences

- [Synchronizing stages within a pass](metal/synchronizing-stages-within-a-pass.md)
- [Synchronizing passes with a fence](metal/synchronizing-passes-with-a-fence.md)
- [Synchronizing passes with producer barriers](metal/synchronizing-passes-with-producer-barriers.md)
- [Synchronizing CPU and GPU work](metal/synchronizing-cpu-and-gpu-work.md)
- [Implementing a multistage image filter using heaps and fences](metal/implementing-a-multistage-image-filter-using-heaps-and-fences.md)
- [MTLStages](metal/mtlstages.md)
- [MTLFence](metal/mtlfence.md)
- [MTLRenderStages](metal/mtlrenderstages.md)
- [MTLBarrierScope](metal/mtlbarrierscope.md)
- [MTL4VisibilityOptions](metal/mtl4visibilityoptions.md)
