C++11
consume operation
memory model
programming
concurrency

What is a consume operation in the C11 Standard?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

memory_order_consume is one of the atomic memory orderings introduced with the C++11 memory model. In theory, it is weaker than acquire and allows synchronization to flow through data dependencies only. In practice, it is one of the most confusing parts of the model and is often treated like acquire by compilers and programmers alike.

Where Consume Fits in the Memory Model

The common orderings are:

  • 'memory_order_relaxed'
  • 'memory_order_consume'
  • 'memory_order_acquire'
  • 'memory_order_release'
  • 'memory_order_acq_rel'
  • 'memory_order_seq_cst'

memory_order_consume is intended for a narrow case: a thread loads a value from an atomic, and later operations depend on that loaded value. The standard says those dependent operations should observe writes that were published with a matching release.

That is weaker than acquire because only dependency-ordered operations are constrained, not all later reads and writes.

The Intended Producer-Consumer Pattern

The classic example is publishing a pointer:

cpp
1#include <atomic>
2#include <iostream>
3
4struct Data {
5    int value;
6};
7
8std::atomic<Data*> ptr{nullptr};
9
10void publish(Data* p) {
11    p->value = 42;
12    ptr.store(p, std::memory_order_release);
13}
14
15void consume() {
16    Data* p = ptr.load(std::memory_order_consume);
17    if (p != nullptr) {
18        std::cout << p->value << '\n';
19    }
20}

The load of p is dependency-linked to the later dereference p->value. The idea is that this data dependency should be enough to make the written value visible without the full cost of acquire.

Why It Is Rarely Used

The problem is compilers. Tracking dependency chains precisely through optimization is hard. As a result, mainstream compilers have historically taken the conservative route and implemented memory_order_consume as if it were memory_order_acquire.

That means the formal model distinguishes them, but real-world code often gets no practical benefit from using consume. For most projects, acquire is clearer and just as effective.

So the pragmatic guidance is simple:

  • understand what consume was meant to do
  • use acquire unless you have a very specific reason not to

Consume Versus Acquire

With acquire:

  • all later memory operations in the thread are constrained

With consume:

  • only operations data-dependent on the loaded value are constrained

That difference matters theoretically, especially on architectures that can exploit dependency ordering efficiently. But if your toolchain maps consume to acquire anyway, the distinction disappears in practice.

Why Dependency Ordering Is Subtle

Data dependency is not the same thing as program order in a casual sense. Small code changes, compiler transformations, or indirection can break the intended dependency chain. That makes consume-based code hard to reason about and harder to review correctly.

For example, if the loaded atomic value does not directly influence the later memory access in a dependency-preserving way, consume semantics may not apply as you expect.

That fragility is part of why many experienced C++ developers advise avoiding consume altogether.

What to Write Instead

In ordinary concurrent C++ code, prefer:

cpp
Data* p = ptr.load(std::memory_order_acquire);

paired with:

cpp
ptr.store(p, std::memory_order_release);

That is easier to explain, easier to maintain, and matches how many compilers effectively behave for consume anyway.

Common Pitfalls

The biggest mistake is assuming consume is just a cheaper acquire that you can swap in casually. Its guarantees are narrower and depend on subtle data-flow properties.

Another mistake is reasoning about consume only at the source-code level without considering compiler optimizations and the actual implementation reality.

A third issue is using advanced memory orderings before mastering acquire-release synchronization. Most code does not need consume.

Summary

  • 'memory_order_consume is a weak synchronization mode based on dependency ordering.'
  • It is intended to be lighter than acquire, especially for pointer-publication patterns.
  • In practice, many compilers treat consume as acquire.
  • That makes acquire-release the better default for most real programs.
  • If you cannot explain the dependency chain precisely, do not use consume.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.