# C++ Thread Annotations (EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED) and absl::Mutex: A Complete Guide

> Master C++ thread annotations like EXCLUSIVE_LOCKS_REQUIRED with absl::Mutex. Detect data races and deadlocks at compile time using Clang's static analyzer for safer multithreaded code.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: deep-dive
- Published: 2026-07-14

---

**Abseil's thread annotations are zero-cost macros that enable Clang's static thread-safety analyzer to detect data races, missing locks, and deadlock risks at compile time by explicitly declaring which mutexes must be held when calling functions.**

The `abseil/abseil-cpp` library provides a comprehensive thread-safety annotation system that allows developers to express locking requirements directly in source code. By using macros like `EXCLUSIVE_LOCKS_REQUIRED` and `SHARED_LOCKS_REQUIRED` alongside `absl::Mutex`, you can catch concurrency bugs during compilation without incurring any runtime overhead.

## What Are Thread Annotations?

Thread annotations are a set of preprocessor macros defined in [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h) that communicate locking expectations to the Clang static analyzer. These annotations expand to nothing in production builds, ensuring zero runtime cost while providing compile-time verification of thread-safety contracts.

## Core Thread Annotation Types

### LOCKABLE and SCOPED_LOCKABLE

The `LOCKABLE` annotation marks a class as a lock type capable of being tracked by the analyzer. In [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h), `absl::Mutex` is declared with this attribute. The `SCOPED_LOCKABLE` annotation identifies RAII lock guards that acquire locks in their constructors and release them in destructors. The `absl::MutexLock` and `absl::ReaderMutexLock` classes in [`absl/synchronization/mutex_lock.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex_lock.h) carry this annotation.

### EXCLUSIVE_LOCKS_REQUIRED and SHARED_LOCKS_REQUIRED

`EXCLUSIVE_LOCKS_REQUIRED(mutex)` declares that a function must only be called while holding the specified mutex in exclusive (write) mode. Conversely, `SHARED_LOCKS_REQUIRED(mutex)` indicates that the function requires the mutex to be held in shared (read) mode. These annotations are defined in [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h) and generate compile-time warnings if callers fail to acquire the appropriate lock type.

### LOCKS_EXCLUDED

The `LOCKS_EXCLUDED(mutex)` annotation specifies that a function must not be called while holding the listed mutex. This prevents potential deadlock scenarios where a function might attempt to acquire a lock already held by the caller.

### Lock Acquisition and Release Attributes

`EXCLUSIVE_LOCK_FUNCTION(mutex)` and `SHARED_LOCK_FUNCTION(mutex)` annotate functions that acquire locks, while `UNLOCK_FUNCTION(mutex)` marks functions that release them. These attributes allow the analyzer to track lock state across function boundaries and through complex control flow.

### GUARDED_BY and PT_GUARDED_BY

Defined in [`absl/base/attributes.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/attributes.h), `GUARDED_BY(mutex)` marks data members that must only be accessed while holding the associated mutex. The `PT_GUARDED_BY` variant provides similar protection for the data pointed to by a pointer, ensuring thread-safe access to heap-allocated objects.

## How Thread Annotations Work with absl::Mutex

The integration between thread annotations and `absl::Mutex` leverages Clang's `-Wthread-safety` diagnostics to verify locking discipline at compile time. When you annotate a method with `EXCLUSIVE_LOCKS_REQUIRED(mu_)`, the analyzer checks that every call site has acquired `mu_` exclusively—typically via `absl::MutexLock`—before invoking the method.

If a caller violates this contract, Clang emits a diagnostic such as:

```

warning: calling function 'Counter::Increment' without holding exclusive lock 'mu_'

```

Similarly, `absl::MutexLock` uses `SCOPED_LOCKABLE` and `EXCLUSIVE_LOCK_FUNCTION` annotations, allowing the analyzer to understand that the constructor acquires the lock and the destructor releases it. This enables the tool to verify that annotated functions are called within the appropriate scope of a lock guard.

## Practical Implementation Example

The following example demonstrates the complete workflow: declaring a mutex, annotating methods with locking requirements, and using RAII guards to satisfy those requirements.

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

class SharedCounter {
 public:
  // Must hold `mu_` exclusively before calling.
  void Increment() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
    ++value_;
  }

  // May hold `mu_` in shared mode.
  int Get() SHARED_LOCKS_REQUIRED(mu_) const {
    return value_;
  }

 private:
  mutable absl::Mutex mu_;               // The lock.
  int value_ ABSL_GUARDED_BY(mu_) = 0;    // Guarded data.
};

void Example() {
  SharedCounter counter;

  // Correct usage – lock acquired before calling Increment().
  {
    absl::MutexLock lock(&counter.mu_);
    counter.Increment();   // OK: exclusive lock held.
  }

  // Incorrect usage – missing lock; Clang will warn.
  // counter.Increment(); // Warning: call without exclusive lock.

  // Correct shared usage.
  {
    absl::ReaderMutexLock lock(&counter.mu_);
    int v = counter.Get(); // OK: shared lock held.
  }
}

```

In this implementation, the `mu_` member is marked as `LOCKABLE` implicitly through the `absl::Mutex` type, while `value_` uses `ABSL_GUARDED_BY(mu_)` from [`absl/base/attributes.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/attributes.h) to declare that all accesses must occur under the protection of `mu_`.

## Key Source Files

- **[`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h)**: Defines all annotation macros including `EXCLUSIVE_LOCKS_REQUIRED`, `SHARED_LOCKS_REQUIRED`, `LOCKS_EXCLUDED`, and `SCOPED_LOCKABLE`.
- **[`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h)**: Implements `absl::Mutex` with the `LOCKABLE` attribute.
- **[`absl/synchronization/mutex_lock.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex_lock.h)**: Provides RAII guard classes (`absl::MutexLock`, `absl::ReaderMutexLock`) marked as `SCOPED_LOCKABLE`.
- **[`absl/base/attributes.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/attributes.h)**: Supplies `ABSL_GUARDED_BY` and `ABSL_PT_GUARDED_BY` for data member protection.

## Summary

- **Thread annotations** are compile-only macros that express locking requirements to Clang's static analyzer.
- **`EXCLUSIVE_LOCKS_REQUIRED`** enforces exclusive lock ownership, while **`SHARED_LOCKS_REQUIRED`** enforces shared (read) lock ownership before function entry.
- **`absl::Mutex`** integrates with the annotation system through `LOCKABLE` markers in [`absl/synchronization/mutex.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex.h) and RAII guards marked `SCOPED_LOCKABLE` in [`absl/synchronization/mutex_lock.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/synchronization/mutex_lock.h).
- **`GUARDED_BY`** from [`absl/base/attributes.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/attributes.h) protects data members by requiring mutex acquisition on access.
- All annotations impose **zero runtime overhead** and expand to nothing in production builds.

## Frequently Asked Questions

### What happens if I call a function without the required lock?

The Clang static analyzer emits a compile-time warning indicating that the function requires an exclusive or shared lock that is not currently held at the call site. For example, calling a method annotated with `EXCLUSIVE_LOCKS_REQUIRED(mu_)` without holding `mu_` exclusively will generate a diagnostic warning.

### Do thread annotations add runtime overhead?

No. The macros defined in [`absl/base/thread_annotations.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/base/thread_annotations.h) expand to nothing during compilation. They are purely compile-time hints for the static analyzer and impose zero runtime cost in production binaries.

### Which compiler supports thread annotations?

Thread annotations require Clang with the `-Wthread-safety` flag enabled. The static analysis is built into Clang's diagnostics framework and is not available in GCC or MSVC. You must compile with Clang to receive thread-safety warnings.

### Can I use thread annotations with custom lock types?

Yes. You can apply the `LOCKABLE` annotation to any class that implements lock/unlock semantics, and `SCOPED_LOCKABLE` to corresponding RAII guards. This enables the same static analysis for custom synchronization primitives as provided for `absl::Mutex`.