Interlocked.Exchange
Boolean type
concurrency
multithreading
C# programming

Why does Interlocked.Exchange not support Boolean type?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Interlocked.Exchange is meant for atomic state changes, but its API is centered on machine-friendly numeric and reference types rather than bool. In practice, .NET code that needs a lock-free flag usually stores 0 or 1 in an int and uses Interlocked on that field.

Why bool Is Not the Normal Interlocked Primitive

Interlocked operations map closely to CPU-supported atomic instructions. Those instructions are most natural for aligned word-sized values such as integers, pointers, and references. A Boolean expresses a yes-or-no meaning well, but it is not the main type the Interlocked API was designed around.

The design goal of Interlocked is not to support every CLR type. It is to expose a small set of atomic building blocks that map cleanly to the runtime and to common synchronization patterns.

That is why the practical question is not "how do I atomically exchange a bool" but "how do I represent a thread-safe flag in a way that works naturally with the available atomic primitives."

Use an Integer as the Flag

The usual pattern is:

  • '0 means false'
  • '1 means true'

Then use Interlocked.Exchange or Interlocked.CompareExchange on the int.

csharp
1using System;
2using System.Threading;
3
4class Example
5{
6    private int _isRunning;
7
8    public bool TryStart()
9    {
10        int previous = Interlocked.Exchange(ref _isRunning, 1);
11        return previous == 0;
12    }
13
14    public void Stop()
15    {
16        Interlocked.Exchange(ref _isRunning, 0);
17    }
18
19    public bool IsRunning => Volatile.Read(ref _isRunning) == 1;
20}

This gives you atomic updates and predictable memory-visibility behavior without needing a Boolean overload.

Why a Plain bool Is Not Enough

Even if a bool field looks simple, the real concurrency problem is not just whether the write fits in memory. It is whether multiple threads observe the right ordering and whether a state transition is performed atomically.

That is why Interlocked and Volatile exist. They describe intent explicitly:

  • 'Interlocked for atomic read-modify-write operations'
  • 'Volatile.Read and Volatile.Write for visibility and ordering'

A shared Boolean flag can be safe in some limited cases, but once you need atomic transitions such as "set this only if it was previously clear," an integer plus Interlocked is the clearer tool.

Exchange Versus CompareExchange

Many flag problems do not actually want unconditional exchange. They want compare-and-swap semantics:

csharp
1private int _initialized;
2
3public bool InitializeOnce()
4{
5    return Interlocked.CompareExchange(ref _initialized, 1, 0) == 0;
6}

This means "set the flag to 1 only if it is currently 0." That is often the real requirement behind single-initialization or single-entry code paths.

So the absence of a Boolean overload matters less than picking the correct atomic primitive for the state transition you need.

The Broader Lesson

The Interlocked API nudges you toward a useful mental model: choose a representation that works cleanly with low-level atomic operations. For .NET, that usually means using integers or references for lock-free coordination and interpreting them at the application level.

That might feel slightly less elegant than a bool, but it is a more explicit fit for concurrency code.

Common Pitfalls

  • Treating bool as the natural lock-free flag type just because the business meaning is true or false.
  • Using ordinary reads and writes on shared state when the program actually needs atomic transitions or visibility guarantees.
  • Choosing Exchange when the real problem calls for CompareExchange.
  • Forgetting Volatile.Read or another synchronization mechanism when reading the flag later.
  • Writing lock-free code because it looks clever instead of because the concurrency requirements actually justify it.

Summary

  • 'Interlocked.Exchange is built around atomic primitives that map naturally to integers and references.'
  • In .NET, thread-safe flags are commonly represented as int values 0 and 1.
  • Use Interlocked.Exchange for unconditional state changes and CompareExchange for compare-and-swap semantics.
  • The real issue is synchronization and memory visibility, not just whether the value is logically boolean.
  • Pick the representation that matches the atomic operation you need, not just the business meaning of the flag.

Course illustration
Course illustration

All Rights Reserved.