agentleFS
botirkhaltaevbotirkhaltaev/botir-skills/skills/rust-concurrency/SKILL.md

rust-concurrency

Skill4 starsChanged 3 months agoApache-2.0View on GitHub

Low-level concurrency in Rust including atomics, memory ordering, building locks/channels, Send/Sync, and thread synchronization. Use when implementing lock-free data structures, understanding memory ordering, building synchronization primitives, or debugging race conditions.

We split this skill into the rules it gives an agent

1 rule. 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • 0

    Common

    Most of the 6 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    SeqCst: When you need total ordering (rare.

    line 95

“Common” is measured: kept by at least 6 in 10 of the 6 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Rust Concurrency & Atomics

Comprehensive guide based on Rust Atomics and Locks by Mara Bos and The Rust Programming Language Ch. 16.

When to Use This Skill

  • Implementing lock-free or wait-free data structures
  • Understanding Ordering (Relaxed, Acquire, Release, AcqRel, SeqCst)
  • Building custom mutexes, channels, or condition variables
  • Debugging data races or incorrect synchronization
  • Understanding Send, Sync, and thread safety markers
  • Using Arc<Mutex<T>> and Arc<RwLock<T>> patterns
  • Working with std::sync::atomic types

Thread Safety Markers

Send

A type is Send if it can be transferred to another thread. Most types are Send. Notable exceptions: Rc<T>, raw pointers, MutexGuard (on some platforms).

Sync

A type is Sync if &T is Send (safe to share references across threads). Examples: Mutex<T> is Sync (even though T isn't necessarily), Cell<T> is NOT Sync.

// Auto-derived by compiler. Manually implement (unsafe) only when wrapping raw pointers:
unsafe impl Send for MyWrapper {}
unsafe impl Sync for MyWrapper {}

Atomic Operations

Types

AtomicBool, AtomicI8..AtomicI64, AtomicU8..AtomicU64, AtomicUsize, AtomicPtr<T>

Core Operations

use std::sync::atomic::{AtomicU64, Ordering};

let counter = AtomicU64::new(0);

counter.store(42, Ordering::Release);           // write
let val = counter.load(Ordering::Acquire);      // read
let old = counter.swap(100, Ordering::AcqRel);  // exchange

// Fetch-and-modify (returns OLD value)
counter.fetch_add(1, Ordering::Relaxed);
counter.fetch_sub(1, Ordering::Relaxed);
counter.fetch_or(mask, Ordering::Relaxed);
counter.fetch_and(!mask, Ordering::Relaxed);

// Compare-and-swap
let result = counter.compare_exchange(
    expected,        // current expected value
    new_value,       // value to store if current == expected
    Ordering::AcqRel,  // ordering on success
    Ordering::Acquire,  // ordering on failure
);
// Returns Ok(old) on success, Err(actual) on failure

Memory Ordering

OrderingGuarantees
RelaxedAtomicity only; no ordering with other operations
AcquireLoads: all subsequent reads/writes see effects before the paired Release
ReleaseStores: all prior reads/writes are visible to the paired Acquire
AcqRelBoth Acquire and Release (for read-modify-write ops)
SeqCstTotal global ordering; all threads see the same order

Acquire-Release Pattern

// Thread A (producer)
DATA.store(value, Ordering::Relaxed);     // write data
READY.store(true, Ordering::Release);      // publish flag

// Thread B (consumer)
while !READY.load(Ordering::Acquire) {}    // wait for flag
let val = DATA.load(Ordering::Relaxed);    // guaranteed to see value

When to Use What

  • Relaxed: Simple counters, statistics, progress indicators
  • Acquire/Release: Publish data between threads (producer-consumer)
  • SeqCst: When you need total ordering (rare; usually overkill)

Building a SpinLock

use std::sync::atomic::{AtomicBool, Ordering};
use std::cell::UnsafeCell;

pub struct SpinLock<T> {
    locked: AtomicBool,
    value: UnsafeCell<T>,
}

unsafe impl<T: Send> Sync for SpinLock<T> {}

impl<T> SpinLock<T> {
    pub fn lock(&self) -> &mut T {
        while self.locked.swap(true, Ordering::Acquire) {
            std::hint::spin_loop();  // CPU hint: we're spinning
        }
        unsafe { &mut *self.value.get() }
    }

    pub fn unlock(&self) {
        self.locked.store(false, Ordering::Release);
    }
}

Standard Library Primitives

Mutex<T>

use std::sync::{Arc, Mutex};

let data = Arc::new(Mutex::new(vec![]));
let data_clone = Arc::clone(&data);

std::thread::spawn(move || {
    let mut lock = data_clone.lock().unwrap();
    lock.push(42);
});  // MutexGuard dropped → lock released

RwLock<T>

use std::sync::RwLock;

let lock = RwLock::new(HashMap::new());
// Multiple readers simultaneously
let r = lock.read().unwrap();
// Exclusive writer
let mut w = lock.write().unwrap();

Channels (mpsc)

use std::sync::mpsc;

let (tx, rx) = mpsc::channel();
let tx2 = tx.clone();  // multiple producers

std::thread::spawn(move || tx.send("hello").unwrap());
std::thread::spawn(move || tx2.send("world").unwrap());

for msg in rx { println!("{msg}"); }

Reference Map

  • references/atomics-ordering.md — atomic types, operations, memory ordering in depth
  • references/building-primitives.md — implementing Mutex, Channel, Condvar from atomics
  • references/thread-patterns.md — Arc+Mutex, scoped threads, thread pools, parking

Key References

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.