К основному содержанию
скилл CX Codex

concurrency-debugging — скилл для Claude Code: разбор гонок и дедлоков

Скилл ведёт агента по отчётам ThreadSanitizer, графам блокировок Helgrind и зависшим потокам в GDB. Пригодится, когда программа падает или виснет на многопоточке.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add mohitmishra786/low-level-dev-skills --skill concurrency-debugging -a claude-code
Открыть на GitHub

Что делает concurrency-debugging

Скилл описывает порядок разбора конкурентных багов: как читать отчёт TSan, как искать нарушение порядка блокировок через Helgrind, как вытащить зависшие потоки в GDB. Сборка под TSan идёт через clang -fsanitize=thread -g -O1 или gcc -fsanitize=thread -g -O1, запуск Helgrind — через valgrind --tool=helgrind --log-file=helgrind.log ./prog.

Внутри есть таблица типичных гонок с исправлениями: чтение и запись глобала без мьютекса, двойная проверка блокировки без atomic, += по общему счётчику, изменение контейнера во время обхода. Отдельный раздел про std::atomic — почему compare_exchange_strong нужен там, где if (counter == 0) counter = 1 даёт TOCTOU-гонку, и почему memory_order_relaxed не годится для флага готовности данных. Дальше разбирается happens-before: sequenced-before внутри потока, synchronizes-with между потоками, создание и join потока, мьютекс.

Для Rust скилл напоминает про Arc<Mutex<T>> и гарантии на этапе компиляции. Учтите: разбор идёт по C++ и Rust, а инструменты в примерах — clang, gcc, valgrind, gdb; если у вас другой тулчейн, примеры придётся перекладывать самому.

Какие задачи решает

  • прочитать отчёт ThreadSanitizer и найти конфликтующие обращения к адресу
  • найти нарушение порядка захвата блокировок до того, как оно даст дедлок
  • определить, какие потоки зависли и какой мьютекс каждый держит
  • поймать TOCTOU-гонку в составной операции над std::atomic
  • разложить happens-before между потоками в C++ или Rust

Примеры запросов агенту

  • ThreadSanitizer выдал data race, помоги прочитать отчёт и предложи исправление
  • Программа зависла на многопоточке — покажи, как найти дедлок через GDB
  • Проверь, правильно ли я расставил memory_order в этом коде

Как установить concurrency-debugging

1Через Skills CLI (Vercel)

npx skills add mohitmishra786/low-level-dev-skills --skill concurrency-debugging -a claude-code

2Вручную: положить файлы

~/.claude/skills/concurrency-debugging/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/concurrency-debugging/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Из того же набора62

cargo-workflows Скилл ведёт агента по воркспейсам Cargo, фичам, build.rs, кэшу сборки и аудиту зависимостей. Пригодится, когда Rust-проект разрастается до нескольких крейтов. CX Codex +1 558установок cpp-modules Скилл для работы с модулями C++20: именованные модули, партиции, header units, сборка через CMake и флаги компиляторов. CX Codex +1 555установок rust-security Скилл для проверки Rust-проектов на уязвимости: cargo-audit, cargo-deny, RUSTSEC, безопасный FFI, фаззинг и Miri. CX Codex +1 544установок debug-optimized-builds Помогает разобраться, почему GDB показывает «value optimized out» и как вообще отлаживать код, собранный с оптимизацией. CX Codex +1 533установок linker-scripts Помогает писать и править скрипты компоновщика GNU ld для bare-metal: регионы памяти, VMA и LMA, инициализация .bss и .data. CX Codex +1 523установок wasm-emscripten Скилл ведёт агента через сборку C и C++ в WebAssembly: подбор флагов emcc, экспорт функций, модель памяти, Asyncify и отладка .wasm. CX Codex +1 513установок zig-debugging Скилл для ИИ-агента: разбирает паники Zig, error return traces и сессии GDB/LLDB. Пригодится, когда программа падает, а стек нечитаемый. CX Codex +1 511установок zig-build-system Помогает агенту писать и отлаживать build.zig: исполняемые файлы, библиотеки, C-исходники, опции сборки и тесты. CX Codex +1 508установок

Похожие

m07-concurrency actionbook Помогает разбирать конкурентный и асинхронный Rust-код: выбрать потоки, async/await, каналы или синхронизацию. Нужен при ошибках Send/Sync, дедлоках и гонках. CX Codex +1 3 500установок debugging tursodatabase Скилл по отладке tursodb: сравнить байткод с SQLite, включить трейс-логи, прогнать ThreadSanitizer, воспроизвести баг по seed и замерить стек. CX Codex +1 1 300установок memory-safety-patterns Seth Hobson Скилл помогает писать код на Rust, C++ и C с учётом владения памятью, RAII и управления ресурсами. Подойдёт для системного кода и поиска ошибок памяти. CX Codex 11 746установок golang-concurrency samber Скилл задаёт правила для конкурентного кода на Go: жизненный цикл горутин, каналы и select, мьютексы, errgroup, singleflight, воркер-пулы и fan-out/fan-in пайплайны. CX Codex +1 41 800установок swift-concurrency AvdLee Помогает находить ошибки Swift Concurrency, переводить callback-код на async/await и готовить проект к Swift 6. Пригодится для диагностики изоляции и гонок данных. CX Codex +1 17 000установок swift-concurrency-expert Dimillian Скилл проверяет и исправляет проблемы параллелизма в Swift 6.2+: добавляет Sendable, применяет @MainActor, решает предупреждения об изоляции акторов и переводит completion handlers на async/await. CX Codex +1 2 000установок

Рядом в теме «Языки программирования»

Все скиллы по теме «Языки программирования» →

Вопросы о concurrency-debugging

Как установить concurrency-debugging в Claude?

Выполните npx skills add mohitmishra786/low-level-dev-skills --skill concurrency-debugging -a claude-code. Скилл окажется в ~/.claude/skills/concurrency-debugging/SKILL.md.

Что делает concurrency-debugging?

Проводит агента по диагностике гонок и дедлоков: разбор отчётов TSan, анализ порядка блокировок в Helgrind, поиск зависших потоков в GDB, типовые ошибки с std::atomic и рассуждения о happens-before.

С какими языками работает скилл?

Примеры и рассуждения построены на C++ и Rust. Инструменты в разборах — ThreadSanitizer, Helgrind, GDB.

Исходный текст

SKILL.md · MIT
---
name: concurrency-debugging
description: Concurrency debugging skill for diagnosing data races and deadlocks. Use when reading TSan race reports, debugging deadlocks with GDB thread inspection, analyzing lock-order graphs with Helgrind, identifying std::atomic misuse patterns, or reasoning about happens-before in C++ and Rust. Activates on queries about data races, TSan reports, deadlocks, Helgrind, lock ordering, thread sanitizer output, or atomic ordering issues.
---

# Concurrency Debugging

## Purpose

Guide agents through diagnosing and fixing concurrency bugs: reading ThreadSanitizer race reports, using Helgrind for lock-order analysis, detecting deadlocks with GDB thread inspection, identifying common `std::atomic` misuse patterns, and applying happens-before reasoning in C++ and Rust.

## Triggers

- "ThreadSanitizer reported a data race — how do I read the report?"
- "My program deadlocks — how do I debug it?"
- "How do I use Helgrind to find threading bugs?"
- "Am I using std::atomic correctly?"
- "How does happens-before work in C++ memory ordering?"
- "How do I find which threads are deadlocked in GDB?"

## Workflow

### 1. ThreadSanitizer (TSan) — race detection

```bash
# Build with TSan
clang -fsanitize=thread -g -O1 -o prog main.c
# or GCC
gcc -fsanitize=thread -g -O1 -o prog main.c

# Run (TSan intercepts memory accesses at runtime)
./prog

# TSan-specific options
TSAN_OPTIONS="halt_on_error=1:second_deadlock_stack=1" ./prog
```

Reading a TSan report:

```text
WARNING: ThreadSanitizer: data race (pid=12345)
  Write of size 4 at 0x7f1234 by thread T2:
    #0 increment /src/counter.c:8:5              ← access site in T2
    #1 worker_thread /src/counter.c:22:3

  Previous read of size 4 at 0x7f1234 by thread T1:
    #0 read_counter /src/counter.c:3:14          ← conflicting access in T1
    #1 main /src/counter.c:30:5

  Thread T2 created at:
    #0 pthread_create .../tsan_interceptors.cpp
    #1 main /src/counter.c:28:3

SUMMARY: ThreadSanitizer: data race /src/counter.c:8:5 in increment
```

How to read:
1. Line 1: type of access (write/read) and address
2. Stack under "Write of size": the thread that performed the write
3. Stack under "Previous read/write": the conflicting thread
4. "Thread T2 created at": where the thread was spawned
5. Fix: the `increment` and `read_counter` functions access the same address without synchronization

Common races and fixes:

| Race pattern | Fix |
|-------------|-----|
| Read/write on global without lock | Add mutex or use `std::atomic` |
| Double-checked locking without `atomic` | Use `std::once_flag` + `std::call_once` |
| `+=` on shared integer | Use `std::atomic<int>::fetch_add()` |
| Container modified while iterated | Lock entire critical section |
| `shared_ptr` ref count race | Already safe (ref count is atomic); but pointed-to object may not be |

### 2. Helgrind — lock-order and race detection

Helgrind uses Valgrind infrastructure to detect lock ordering violations (potential deadlocks) and data races:

```bash
# Run with Helgrind
valgrind --tool=helgrind --log-file=helgrind.log ./prog

# Lock order violation report
==1234== Thread #3: lock order "0x... M2" after "0x... M1"
==1234== observed (incorrect) order
==1234==    at pthread_mutex_lock (helgrind/...)
==1234==    by worker2 /src/worker.c:45           ← T3 takes M2 then M1
==1234==
==1234== required order established by acquisition of lock at address 0x... M1
==1234==    at pthread_mutex_lock
==1234==    by worker1 /src/worker.c:31            ← T1 takes M1 then M2
```

Lock-order violation = potential deadlock:
- Thread T1 acquires M1, then tries M2
- Thread T2 acquires M2, then tries M1
- Both can deadlock if they race

Fix: enforce a consistent global lock ordering. Always take M1 before M2 everywhere.

### 3. Deadlock detection with GDB

```bash
# Attach GDB to a deadlocked process
gdb -p $(pgrep prog)

# Or run under GDB then trigger deadlock

(gdb) info threads          # list all threads and current state
# * 1  Thread 0x... (LWP 1234) "prog" ... in __lll_lock_wait ()
#   2  Thread 0x... (LWP 1235) "prog" ... in __lll_lock_wait ()
# Threads blocked in __lll_lock_wait = waiting for mutex

(gdb) thread 1
(gdb) bt                    # show which mutex thread 1 is waiting for

(gdb) thread 2
(gdb) bt                    # show which mutex thread 2 holds/waits

# Find the mutex owner
(gdb) p ((pthread_mutex_t*)0x601090)->__data.__owner   # Linux glibc mutex
# prints TID of owning thread

# Python script to dump all mutex owners (GDB 7+)
python
import gdb
for t in gdb.selected_inferior().threads():
    t.switch()
    print(f"Thread {t.num}: {gdb.execute('bt 3', to_string=True)}")
end
```

### 4. std::atomic misuse patterns

```cpp
// WRONG: atomic variable, but non-atomic compound operation
std::atomic<int> counter{0};
if (counter == 0) counter = 1;   // not atomic together! TOCTOU race

// CORRECT: use compare_exchange
int expected = 0;
counter.compare_exchange_strong(expected, 1);

// WRONG: relaxed ordering for sync flag
std::atomic<bool> ready{false};
// Producer:
data = 42;
ready.store(true, std::memory_order_relaxed);  // WRONG: no happens-before

// CORRECT: release-acquire for publishing data
// Producer:
data = 42;
ready.store(true, std::memory_order_release);   // syncs with acquire

// Consumer:
if (ready.load(std::memory_order_acquire)) {    // syncs with release
    use(data);  // safe to read data here
}

// WRONG: using data across threads without atomic/mutex
// int shared_data;  // non-atomic — UB on concurrent access

// CORRECT: protect with mutex or make atomic
std::mutex mtx;
std::unique_lock lock(mtx);
shared_data = 42;
```

### 5. Happens-before reasoning

In C++, happens-before is established by:

```
Sequenced-before (within a thread):
  Statement A comes before B in code → A happens-before B

Synchronizes-with (across threads):
  store(release) → load(acquire) on SAME atomic variable
    → store happens-before load
    → everything before store happens-before everything after load

Thread creation/join:
  spawn(T) → any action in T         (create synchronizes-with)
  any action in T → join(T)          (join synchronizes-before)

Mutex:
  unlock(M) → lock(M) (next acquirer)
```

```cpp
// Establishing happens-before across threads
std::atomic<int> flag{0};
int data = 0;

// Thread 1:
data = 42;                        // A
flag.store(1, memory_order_release); // B: A sequenced-before B

// Thread 2:
while (flag.load(memory_order_acquire) != 1) {}  // C: synchronizes-with B
int x = data;                     // D: C sequenced-before D
// D reads 42: A happens-before B synchronizes-with C sequenced-before D
//             → A happens-before D
```

### 6. Rust concurrency — compile-time guarantees

Rust prevents data races at compile time via ownership:

```rust
use std::sync::{Arc, Mutex};
use std::thread;

// Shared mutable state: Arc<Mutex<T>>
let counter = Arc::new(Mutex::new(0u32));

let c = Arc::clone(&counter);
let t = thread::spawn(move || {
    let mut val = c.lock().unwrap();
    *val += 1;
});

t.join().unwrap();
println!("{}", *counter.lock().unwrap());

// Rust prevents:
// - Sharing &mut T across threads (Sync not impl for &mut T)
// - Moving non-Send types to threads (compiler error)
// Use TSAN_OPTIONS with cargo test if TSan checks are needed:
// RUSTFLAGS="-Z sanitizer=thread" cargo +nightly test
```

## Related skills

- Use `skills/runtimes/sanitizers` for TSan build flags and other sanitizers
- Use `skills/profilers/valgrind` for Helgrind and Memcheck integration
- Use `skills/debuggers/gdb` for advanced GDB thread inspection
- Use `skills/low-level-programming/memory-model` for C++/Rust memory ordering theory

© mohitmishra786 · MIT · mohitmishra786/low-level-dev-skills

Смотрите также

Спонсоры проекта

Компании, которые помогают держать аналитику открытой