# How to Use Abseil C++ `absl::Mutex`: A Complete Guide with Examples

> Master absl mutex in C++ with RAII guards like MutexLock for exclusive access and Condition for predicate-based waiting. Learn effective synchronization techniques for your C++ projects.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Use `absl::Mutex` with RAII guards like `MutexLock` and `ReaderMutexLock` for exclusive and shared access, and employ `Condition` with `LockWhen` or `Await` for predicate-based waiting.**

`absl::Mutex` is the primary synchronization primitive in the Abseil C++ library (`abseil/abseil-cpp`). It provides non-recursive exclusive locking, shared reader-writer semantics, and efficient condition-based waiting APIs. This guide covers the essential patterns for thread-safe data access using the implementation found in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h).

## Declaring and Basic Locking

The `absl::Mutex` class defined in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h) provides a non-reentrant lock that must be acquired before accessing shared state.

### Static Initialization with `ABSL_CONST_INIT`

For global or static mutexes, use the `ABSL_CONST_INIT` macro to ensure constant initialization and avoid dynamic initialization order issues:

```cpp
#include "absl/synchronization/mutex.h"

ABSL_CONST_INIT absl::Mutex global_mu;
int global_counter ABSL_GUARDED_BY(global_mu) = 0;

```

### Exclusive Locking with `MutexLock`

Always prefer **RAII guards** over manual `lock()` and `unlock()` calls. The `absl::MutexLock` class acquires the mutex in its constructor and releases it in its destructor, guaranteeing exception-safe unlocking:

```cpp
void IncrementCounter() {
  absl::MutexLock lock(&global_mu);  // Acquires exclusive lock
  ++global_counter;                  // Safe mutation
}                                    // Automatic unlock

```

Direct manual locking is available via `mu.lock()` and `mu.unlock()`, but these are discouraged in modern C++ except when implementing custom guard classes.

## Reader-Writer Locking Patterns

`absl::Mutex` supports shared ownership for concurrent reads. According to the source in `absl/synchronization/mutex.cc`, the implementation optimizes for the common case of uncontended locks while allowing reader parallelism.

### Shared Locks with `ReaderMutexLock`

Use `absl::ReaderMutexLock` (or `mu.lock_shared()`) when multiple threads need concurrent read access:

```cpp
int ReadCounter() {
  absl::ReaderMutexLock lock(&global_mu);  // Acquires shared lock
  return global_counter;                   // Safe concurrent read
}                                          // Automatic unlock_shared

```

### Exclusive Locks with `WriterMutexLock`

Use `absl::WriterMutexLock` (or `mu.lock()`) for write operations that require exclusive access. This blocks until all readers have exited:

```cpp
void ResetCounter() {
  absl::WriterMutexLock lock(&global_mu);  // Acquires exclusive lock
  global_counter = 0;                      // Exclusive write
}

```

The header [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h) provides macros like `ABSL_GUARDED_BY` to document which mutex protects which data, enabling static analysis tools.

## Condition-Based Waiting

`absl::Mutex` provides high-level condition variable abstractions that are safer than raw `CondVar` (also available in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h)).

### Building a `Condition` Predicate

A `Condition` is a lightweight callable that evaluates a predicate. It must be stateless and return a boolean. You can construct it from a function pointer, member method, or lambda:

```cpp
int target_value = 100;
absl::Condition ready([](int* counter, int target) { return *counter >= target; },
                      &global_counter, target_value);

```

### Blocking with `LockWhen` and `Await`

**`LockWhen`** atomically waits for the condition to become true and acquires the mutex. This is more efficient than spinning:

```cpp
void WaitForTarget(int target) {
  absl::Condition ready([](int* counter, int target) { return *counter >= target; },
                        &global_counter, target);
  
  global_mu.LockWhen(ready);  // Blocks until predicate true AND lock acquired
  // Predicate is guaranteed true here, lock held
  ProcessThresholdReached();
  global_mu.Unlock();
}

```

**`Await`** is similar but requires you to already hold the mutex. It releases the mutex while waiting and reacquires it upon return:

```cpp
global_mu.Lock();
while (global_counter < target) {
  global_mu.Await(absl::Condition([](int* c, int t) { return *c >= t; }, 
                                  &global_counter, target));
}
global_mu.Unlock();

```

### Timed Waits with `LockWhenWithTimeout`

For time-bounded blocking, use `LockWhenWithTimeout` or `AwaitWithTimeout`. These return `true` if the predicate became true, or `false` if the timeout elapsed first:

```cpp
bool success = global_mu.LockWhenWithTimeout(
    absl::Condition([](int* c) { return *c > 0; }, &global_counter),
    absl::Seconds(5));

```

The timeout implementation uses [`absl/synchronization/internal/kernel_timeout.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/internal/kernel_timeout.h) to handle platform-specific deadline management.

## Debug Utilities and Annotations

The `absl::Mutex` API includes built-in debugging features defined in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h) to detect deadlocks and logic errors.

### Thread Safety Annotations

Include [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h) to use annotations that document locking requirements:

```cpp
int shared_data ABSL_GUARDED_BY(mu);

void UpdateData() ABSL_EXCLUSIVE_LOCK_FUNCTION(mu);
void ReadData() ABSL_SHARED_LOCK_FUNCTION(mu);

```

### Runtime Debugging Checks

Enable diagnostic checks to verify locking assumptions:

- **`mu.AssertHeld()`**: Verifies the current thread holds an exclusive lock.
- **`mu.AssertReaderHeld()`**: Verifies the current thread holds a shared lock.
- **`mu.AssertNotHeld()`**: Verifies the current thread does not hold the mutex.

For advanced debugging, use `EnableInvariantDebugging` to register a function that validates invariants on every lock/unlock, and `EnableDebugLog` to trace all operations:

```cpp
mu.EnableInvariantDebugging([](void*) { return CheckInvariants(); }, nullptr);
mu.EnableDebugLog("my_mutex");

```

## Summary

- **Declare** mutexes in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h) using `ABSL_CONST_INIT` for static storage.
- **Lock** using RAII guards: `MutexLock` for exclusive access, `ReaderMutexLock` for shared read access.
- **Wait** for predicates using `Condition` with `LockWhen` or `Await` to avoid busy-waiting.
- **Timeout** operations using `LockWhenWithTimeout` and `AwaitWithTimeout` with `absl::Duration`.
- **Debug** with `AssertHeld`, `EnableInvariantDebugging`, and thread annotations from [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h).

## Frequently Asked Questions

### Is `absl::Mutex` recursive?

No, `absl::Mutex` is non-recursive (non-reentrant). Attempting to acquire a lock that the current thread already holds results in undefined behavior or deadlock. Use separate mutexes or restructure your code to avoid recursive locking.

### What is the difference between `MutexLock` and `WriterMutexLock`?

Both acquire exclusive locks, but `absl::MutexLock` is the standard RAII guard for exclusive access, while `absl::WriterMutexLock` explicitly communicates intent in codebases mixing reader and writer locks. Functionally, they are identical; prefer `MutexLock` for exclusive access unless you need the semantic clarity of "writer" in a reader-writer context.

### How does `LockWhen` differ from a standard condition variable?

`LockWhen` combines the wait and lock acquisition into a single atomic operation. Unlike traditional condition variables where you wait while holding the mutex, `LockWhen` waits for the predicate **before** acquiring the lock, reducing contention. According to [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h), this is more efficient than the manual `while (!pred) wait()` loop pattern.

### Can I use `absl::Mutex` with `std::lock_guard`?

No, `absl::Mutex` is not compatible with `std::lock_guard` or other standard C++ mutex wrappers because it does not implement the standard `Lockable` interface. Always use Abseil's provided RAII classes: `absl::MutexLock`, `absl::ReaderMutexLock`, and `absl::WriterMutexLock`.