Concurrency Comparisons
Side-by-side trade-offs where neither column wins. The workload, the runtime and how much correctness risk you can carry decide — and each comparison ends with the verdict that follows from that, not from a preference.
Concurrency vs parallelismThreads vs processesAsync vs threadsEvent loop vs thread poolMutex vs semaphoreOptimistic vs pessimistic concurrency controlLock-based vs lock-freeBounded vs unbounded queue
Lock-based vs lock-free
Lock-free is a progress guarantee — at least one thread always advances — and not a performance claim. Presented as an optimization it is one of the most expensive mistakes available to a team.
| Dimension | Lock-based | Lock-free |
|---|---|---|
| Guarantee | Mutual exclusion; progress depends on the holder finishing | Some thread always makes progress, whatever the others do |
| If a task is descheduled inside | Everyone waiting is stuck until it is scheduled again | Others continue; that is the entire point |
| Uncontended cost | An atomic operation plus a little bookkeeping | An atomic operation |
| Contended cost | Block, context switch, wake — expensive but bounded | CAS retries burning CPU and cache-line traffic |
| Multi-word invariants | Straightforward — lock the region | Very hard; usually needs a redesign of the data structure |
| Memory reclamation | Not a problem — the lock says when nobody is looking | A hard open problem: hazard pointers, epochs, RCU |
| Failure modes | Deadlock, convoy, starvation, priority inversion | Livelock, ABA, torn invariants, memory-ordering bugs |
| Reviewability | Most engineers can review it correctly | Very few can, and the bugs are the subtle kind |
Use Lock-based when
- Essentially always, as the starting point.
- The invariant spans more than one word.
- The team must be able to review and maintain the result.
Use Lock-free when
- A profile shows the lock is the bottleneck and the region cannot shrink.
- Progress must survive a thread being descheduled — real-time or signal contexts.
- You are using a well-tested library structure rather than writing your own.
Verdict
Use a lock. If contention is genuinely the bottleneck, first shrink the critical section, then shard the lock, then remove the sharing. Hand-written lock-free code is the last resort, and it should arrive with a benchmark and a memory-reclamation story.