# Concurrency Patterns — Derived Rules > Derives from `domains/concurrency/first-principles.md`. Common concurrency patterns and when to use them. ## Pattern 1: Message Passing (P5 Lock Minimization) - Threads/goroutines communicate via channels/queues, not shared memory. - "Don't communicate by sharing memory; share memory by communicating." (Go proverb) - Use when the data flows naturally in one direction. Avoids locks entirely. ## Pattern 2: Read-Write Lock (P5 Lock Minimization) - Multiple readers, one writer. A `RwLock` allows concurrent reads, exclusive writes. - Use when reads vastly outnumber writes (e.g., a config cache). - Avoid when writes are frequent — the lock degrades to a mutex. ## Pattern 3: Actor Model (P2 Single Responsibility) - Each actor owns its state. Actors communicate via messages. No shared state. - Use for isolated, long-lived workers (e.g., a session handler, a chat room). - Erlang/Akka/Pony are built on this. Implementable in any language with channels. ## Pattern 4: Immutable Data Structures (P1 Immutability by Default) - Data is never mutated; a "change" creates a new value. Old values are safe to share. - Use in functional languages (Haskell, Clojure) or via persistent data structures (Immer.js). - Eliminates entire classes of races. The trade-off is allocation cost. ## Pattern 5: Bounded Queue with Backpressure (P9 Bounded Queues) - A queue with a max size. When full, the producer is blocked or signaled. - Use to bound memory and propagate slowness from consumer to producer. - An unbounded queue hides a slow consumer until OOM. Always bound. ## Pattern 6: Timeout on Every Block (P8 Timeout Discipline) - Every blocking call (lock acquire, queue send, HTTP request) has a timeout. - Use a timeout, not a forever-block. Forever is not a duration. - On timeout: cancel, retry, or fail. Do not hang. ## Pattern 7: Cancellation Propagation (P7 Cancellation Support) - A cancellation signal propagates to all spawned work. Cancel the parent, the children stop. - Use context (`context.Context` in Go, `AbortController` in JS, `CancellationToken` in C#). - Cancellation is fast and complete. No orphaned goroutines/threads. ## Pattern 8: Lock-Free Where Possible (P5) - Atomic operations (compare-and-swap) for simple state. No lock. - Use for counters, flags, simple pointers. - Avoid for complex state — lock-free code is subtle and easy to get wrong. ## What Violates Concurrency Patterns | Violation | Pattern | |-----------|---------| | Shared mutable state with no lock | (race, P1) | | Unbounded queue | P5 (OOM) | | `channel.send()` with no timeout | P6 (hang) | | Spawned goroutine with no cancellation | P7 (orphan) | | A mutex held across an I/O call | P3 (lock scope) | | `sync.Mutex` for a counter | P8 (use atomic) |