C++ Static Thread Safety & Synchronization Guidelines
SkillDev toolsLets your agent write C++ code with correct thread safety annotations and locking patterns.
Use C++ Static Thread Safety & Synchronization Guidelines in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add C++ Static Thread Safety & Synchronization Guidelines and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the C++ Static Thread Safety & Synchronization Guidelines skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
No other account needed.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
About this skill
Enforce C++ static thread safety annotations and correct synchronization primitives. Use this skill when designing multi-threaded classes or editing guarded member fields.
What this skill tells your AI
The instructions your AI receives, as published by google/filament in skills/cpp_static_thread_safety/SKILL.md and read by ahel’s review.
Filament leverages Clang's static thread safety analysis to verify lock holding requirements at compile-time. All multi-threaded classes must use explicit capability annotations to guarantee race-free state access.
1. Selecting the Correct Lock Primitive
- Filament Primitives (
utils::Mutex&utils::Condition) — MANDATORY:- Rule: All engine, backend, and utility code under
filament/must useutils::Mutexandutils::Conditionexclusively. Do not usestd::mutexorstd::condition_variable. - Deadlock & Order Debugging:
utils::Mutextransparently integrates with Filament's compile-time lock debugging facility (FILAMENT_DEBUG_MUTEX/-u). When enabled, it maintains a global cycle dependency graph via BFS duringlock()andtry_lock(), immediately trapping lock-order inversions and self-deadlocks with exactCallStacktraces. Any locks defined viastd::mutexbypass this tracker entirely and remain invisible to deadlock diagnostics. - Memory & Cache Hygiene: On Android and Linux (
linuxutil::Mutex),utils::Mutexis only 4 bytes (a single atomic futex word) versus 40 bytes forstd::mutex. For structures allocated in large volumes or embedded in handles/fences, this 10x size reduction prevents struct bloat and maintains cache-line density. - Condition Variable Support:
utils::Condition(Condition::wait/wait_until) is explicitly templated (template <typename M>) to work seamlessly withUniqueLock<utils::Mutex>for producer-consumer queues and blocking wait loops. - Priority Inversion Reality: C++ standard
std::mutex(pthread_mutex_t) does not provide priority inheritance out of the box (PTHREAD_PRIO_NONE). Therefore,std::mutexoffers zero priority inversion protection overutils::Mutex.
- Rule: All engine, backend, and utility code under
2. Lock Guard & RAII Lifetime Conventions
- Immutability Invariant: Use
LockGuard constas the default for all standard synchronized blocks to guarantee scope-bound read-only lock scopes.// Correct utils::LockGuard const lock(mLock); - Condition Variables Overloads: Use
UniqueLock(non-const) strictly when passing locks to condition variables (wait(lock)) or when explicit.unlock()/.lock()boundaries are required for performance or deadlock prevention. - Lock Dependency: Any source file (
.cpp) that instantiatesLockGuardorUniqueLockmust explicitly include the matching utility header:#include <utils/Mutex.h>
3. Resolving Clang's Lambda Closure Limitations
Clang evaluates C++ anonymous closures (lambdas) as separate context boundaries. Because lambdas lack capability attributes, standard condition variable waits passing local predicates (e.g., using std::ranges::all_of) will trigger false-positive thread safety errors.
To resolve this, use one of the following approved patterns:
Pattern A: Inner Lambda Bypass (Recommended)
Decorate only the CV wait predicate lambda operator with UTILS_NO_THREAD_SAFETY_ANALYSIS to ignore nested boundaries while preserving outer compile-time checks:
UniqueLock lock(mQueueLock);
mQueueCondition.wait(lock, [this]() UTILS_NO_THREAD_SAFETY_ANALYSIS {
return mExitRequested ||
(!std::ranges::all_of(mQueues, [](auto&& q) { return q.empty(); }));
});
Pattern B: Manual Loop Inlining
If the check is flat, completely inline the CV predicate as a standard while loop to bring the member variables directly into the parent function's locked scope:
UniqueLock lock(mLock);
while (mFreeSpace < requiredSize) {
mCondition.wait(lock);
}
4. Dynamic Threading & Preprocessor Safety
- Single-Threaded Parity: All thread safety annotations (
UTILS_GUARDED_BY) are conditionally compiled out on single-threaded configurations. To prevent compile crashes whenFILAMENT_SINGLE_THREADEDis defined, standard annotations are gated byUTILS_HAS_THREADINGincompiler.h.
Signals
- GitHub stars
- 21k
- Forks
- 2k
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
cpp-static-thread-safety- Source
- github.com/google/filament