A comprehensive collection of 50 examples teaching multithreaded programming in the Odin programming language using the POSIX threads library (core:thread) and synchronization primitives (core:sync) for Linux.
MIT License
These examples progress from basic thread creation to advanced synchronization patterns. Each example is self-contained, well-documented, and includes built-in tests to verify correctness.
| Part | Examples | Topics |
|---|---|---|
| 1. Thread Basics | 01-08 | Thread creation, data passing, yield, polymorphic data |
| 2. Basic Synchronization | 09-16 | Mutex, guard, try_lock, recursive mutex, read-write mutex |
| 3. Advanced Synchronization | 17-24 | Condition variables, semaphores, barriers, wait groups |
| 4. Classic Problems | 25-30 | Dining philosophers, readers-writers, bank transfers |
| 5. Thread Pools | 31-36 | Pool basics, parallel for, map, work stealing |
| 6. Advanced Patterns | 37-50 | Ticket mutex, atomics, futures, pipelines, TLS |
Each example can be run independently:
odin run 01_hello_thread.odin -fileTo run all tests:
for f in *.odin; do
echo "Testing $f..."
odin run "$f" -file
doneBasic Thread Creation and Joining
The simplest possible thread example - create a thread, run it, wait for it.
API Covered:
thread.create()- Create a new thread (suspended)thread.start()- Begin thread executionthread.join()- Wait for thread completionthread.destroy()- Free thread resources
Passing Data to Threads
How to pass data to a thread using the data field (rawptr).
API Covered:
thread.Thread.data- Raw pointer for passing data- Type casting with
cast(^T)for data access
Creating and Managing Multiple Threads
Managing arrays of threads, coordinating multiple workers.
API Covered:
- Array of thread pointers
- Loop-based thread creation
- Joining multiple threads
Returning Data from Threads
Techniques for returning results from thread execution.
API Covered:
- Using shared data structures
- Pointer-based result passing
thread.user_indexfor thread identification
Thread Priority and Yielding
Thread priority levels (requires root on Linux) and manual yielding.
API Covered:
thread.Thread.Priorityenum (.Low,.Normal,.High,.Highest)thread.yield()- Voluntarily give up CPU time
Cooperative Multitasking with Yield
Demonstrating cooperative scheduling between threads.
API Covered:
thread.yield()for cooperative scheduling- Thread interleaving patterns
Convenience Thread Creation
Using create_and_start for simpler thread creation.
API Covered:
thread.create_and_start()- Combined create + start- Immediate vs. deferred thread start
Polymorphic Data Passing
Using create_and_start_with_poly_data for type-safe data passing.
API Covered:
thread.create_and_start_with_poly_data()- Type-safe data copy- Automatic data copying (up to 64 bytes on 64-bit systems)
Introduction to Mutexes
Mutual exclusion for protecting shared data.
API Covered:
sync.Mutex- Basic mutex type (zero-initialized)sync.mutex_lock()- Acquire locksync.mutex_unlock()- Release lock
RAII-Style Mutex Guards
Automatic lock release using scoped guards.
API Covered:
sync.guard()- Scoped lock guardsync.Mutex_Guard- Guard typedeferpattern for cleanup
Non-Blocking Lock Attempts
Trying to acquire a lock without blocking.
API Covered:
sync.mutex_try_lock()- Non-blocking lock attempt- Lock acquisition strategies
Recursive (Reentrant) Mutexes
Mutexes that can be locked multiple times by the same thread.
API Covered:
sync.Recursive_Mutex- Reentrant mutex type- Nested locking patterns
Read-Write Mutexes
Multiple readers OR single writer access pattern.
API Covered:
sync.RW_Mutex- Read-write mutexsync.shared_lock()/sync.shared_unlock()- Reader lockssync.mutex_lock()/sync.mutex_unlock()- Writer locks
Understanding Race Conditions
Demonstrating what happens without proper synchronization.
Concepts:
- Data races
- Lost updates
- Importance of synchronization
Thread-Safe Counter
Building a thread-safe counter with mutex protection.
API Covered:
- Encapsulating mutex with data
- Safe increment/decrement operations
Bank Account Example
Classic thread-safe bank account with deposits and withdrawals.
Concepts:
- Critical sections
- Atomic operations on compound data
- Balance consistency
Introduction to Condition Variables
Signaling between threads for coordination.
API Covered:
sync.Cond- Condition variablesync.cond_wait()- Wait for signalsync.cond_signal()- Wake one waitersync.cond_broadcast()- Wake all waiters
Producer-Consumer Pattern
Classic pattern for decoupling data production and consumption.
Concepts:
- Bounded vs unbounded buffers
- Signaling between producers and consumers
- Proper wait loops
Bounded Buffer Implementation
Fixed-size buffer with blocking on full/empty.
API Covered:
- Circular buffer techniques
- Two condition variables (not_full, not_empty)
Introduction to Semaphores
Counting semaphores for resource management.
API Covered:
sync.Sema- Semaphore typesync.sema_post()- Increment (signal)sync.sema_wait()- Decrement (wait)
Resource Pool with Semaphores
Managing a limited pool of resources.
Concepts:
- Connection pooling
- Resource limiting
- Semaphores as counters
Thread Barriers
Synchronization point where all threads must arrive before any proceed.
API Covered:
sync.Barrier- Barrier typesync.barrier_init()- Initialize with party countsync.barrier_wait()- Wait at barrier
Wait Groups
Waiting for a collection of tasks to complete.
API Covered:
sync.Wait_Group- Wait group typesync.wait_group_add()- Add tasks to wait forsync.wait_group_done()- Mark task completesync.wait_group_wait()- Wait for all tasks
One-Time Initialization
Ensuring code runs exactly once, regardless of thread count.
API Covered:
sync.Once- Once typesync.once_do()- Execute exactly once
Dining Philosophers Problem
Classic deadlock-prone problem and its solutions.
Concepts:
- Deadlock conditions
- Resource ordering
- Timeout-based solutions
Readers-Writers Problem
Multiple readers or single writer access pattern.
Concepts:
- Reader preference vs writer preference
- Starvation prevention
Sleeping Barber Problem
Producer-consumer with bounded waiting room.
Concepts:
- Bounded waiting
- Customer drop-off when full
Assembly Line Workers Problem
Coordinated resource sharing among specialized workers.
Concepts:
- Semaphore-based signaling
- Component matching
- Multi-party coordination
Multi-Account Bank Transfers
Safe transfers between multiple accounts.
Concepts:
- Two-phase locking
- Lock ordering to prevent deadlock
- Atomic multi-account operations
Parallel Array Summation
Dividing work across multiple threads.
Concepts:
- Work partitioning
- Result aggregation
- Parallel reduction
Introduction to Thread Pools
Reusing threads for multiple tasks.
API Covered:
thread.Pool- Built-in thread poolthread.pool_init()- Initialize poolthread.pool_start()- Start worker threadsthread.pool_finish()- Wait for completionthread.pool_destroy()- Cleanup
Submitting Multiple Tasks
Adding work to the thread pool.
API Covered:
thread.pool_add_task()- Submit workthread.Task- Task structure- Task procedures and data
Collecting Results from Thread Pool
Gathering results from parallel tasks.
Concepts:
- Result aggregation
- Task completion tracking
Parallel For-Loop Pattern
Distributing loop iterations across threads.
Concepts:
- Loop parallelization
- Chunk sizing
- Load balancing
Parallel Map Operation
Applying a function to all elements in parallel.
Concepts:
- Functional parallelism
- Element-wise transformation
Work Stealing Pattern
Load balancing through work stealing.
Concepts:
- Per-worker queues
- Stealing from busy workers
- Dynamic load balancing
Ticket Mutex (Fair Locking)
FIFO ordering for lock acquisition.
API Covered:
sync.Ticket_Mutex- Fair mutex- Ticket-based ordering
Benaphore (Efficient Mutex)
Atomic + semaphore for efficient locking.
API Covered:
sync.Benaphore- Efficient mutex- Fast-path optimization
Monitor Pattern
Encapsulating mutex and conditions with data.
Concepts:
- Object-oriented synchronization
- Condition predicates
- Monitor invariants
Atomic Operations
Lock-free programming primitives.
API Covered:
sync.atomic_load()- Atomic readsync.atomic_store()- Atomic writesync.atomic_add()- Atomic addsync.atomic_exchange()- Atomic swapsync.atomic_compare_exchange_weak()- CAS
Future/Promise Pattern
Asynchronous computation with deferred results.
Concepts:
- Async computation
- Result futures
- Blocking get vs polling
Pipeline Pattern
Multi-stage data processing with bounded channels.
Concepts:
- Stage-based processing
- Backpressure
- Graceful shutdown
Double Buffering
Overlapping producer and consumer work.
Concepts:
- Front/back buffer swapping
- Latency hiding
- Real-time applications
Token Bucket Rate Limiter
Controlling operation rates with token bucket.
Concepts:
- Rate limiting
- Burst handling
- Time-based refill
Countdown Latch
One-shot synchronization for multiple completions.
Concepts:
- Starting gun pattern
- Waiting for N completions
- vs barriers and wait groups
Cyclic Barrier
Reusable barrier with optional action.
Concepts:
- Multi-phase algorithms
- Barrier action
- Generation counting
Thread Exchanger
Two-party data exchange.
Concepts:
- Paired synchronization
- Data swapping
- Rendezvous pattern
Phaser (Flexible Barrier)
Dynamic barrier with registration/deregistration.
Concepts:
- Dynamic parties
- Tiered synchronization
- Arrive without waiting
Fork-Join Pattern
Divide-and-conquer parallelism.
Concepts:
- Recursive parallelism
- Work splitting
- Result combining
Thread-Local Storage
Per-thread data without synchronization.
API Covered:
@(thread_local)attribute- Per-thread variables
- TLS patterns
| Function | Description |
|---|---|
thread.create(proc) |
Create suspended thread |
thread.start(t) |
Begin execution |
thread.join(t) |
Wait for completion |
thread.destroy(t) |
Free resources |
thread.yield() |
Give up CPU time |
thread.create_and_start(proc) |
Combined create + start |
thread.create_and_start_with_poly_data(data, proc) |
With type-safe data copy |
| Function | Description |
|---|---|
thread.pool_init(&pool, allocator, num_threads) |
Initialize pool |
thread.pool_start(&pool) |
Start workers |
thread.pool_add_task(&pool, proc, data) |
Submit task |
thread.pool_finish(&pool) |
Wait for tasks |
thread.pool_destroy(&pool) |
Cleanup |
| Type | Description |
|---|---|
sync.Mutex |
Basic mutual exclusion |
sync.RW_Mutex |
Read-write mutex |
sync.Recursive_Mutex |
Reentrant mutex |
sync.Ticket_Mutex |
Fair FIFO mutex |
sync.Benaphore |
Efficient mutex |
sync.Cond |
Condition variable |
sync.Sema |
Counting semaphore |
sync.Barrier |
Thread barrier |
sync.Wait_Group |
Task completion tracker |
sync.Once |
One-time initialization |
| Function | Description |
|---|---|
sync.mutex_lock(&m) |
Acquire lock |
sync.mutex_unlock(&m) |
Release lock |
sync.mutex_try_lock(&m) |
Non-blocking attempt |
sync.guard(&m) |
RAII-style guard |
| Function | Description |
|---|---|
sync.shared_lock(&m) |
Acquire read lock |
sync.shared_unlock(&m) |
Release read lock |
sync.mutex_lock(&m) |
Acquire write lock |
sync.mutex_unlock(&m) |
Release write lock |
| Function | Description |
|---|---|
sync.cond_wait(&c, &m) |
Wait for signal |
sync.cond_signal(&c) |
Wake one waiter |
sync.cond_broadcast(&c) |
Wake all waiters |
| Function | Description |
|---|---|
sync.sema_post(&s) |
Increment (signal) |
sync.sema_wait(&s) |
Decrement (wait) |
| Function | Description |
|---|---|
sync.barrier_init(&b, count) |
Initialize with party count |
sync.barrier_wait(&b) |
Wait at barrier |
| Function | Description |
|---|---|
sync.wait_group_add(&wg, n) |
Add n tasks |
sync.wait_group_done(&wg) |
Mark one complete |
sync.wait_group_wait(&wg) |
Wait for all |
| Function | Description |
|---|---|
sync.atomic_load(&v) |
Read atomically |
sync.atomic_store(&v, val) |
Write atomically |
sync.atomic_add(&v, delta) |
Add and return old |
sync.atomic_sub(&v, delta) |
Subtract and return old |
sync.atomic_exchange(&v, new) |
Swap and return old |
sync.atomic_compare_exchange_weak(&v, &expected, new) |
CAS |
Beginners: Start with examples 01-08 to understand thread basics.
Intermediate: Work through examples 09-24 to master synchronization.
Advanced: Study examples 25-36 for classic problems and thread pools.
Expert: Explore examples 37-50 for advanced patterns and lock-free programming.
- Odin Programming Language
- POSIX Threads (pthreads) specification
- Classic concurrency literature