o
odinpkg.dev
packages / library / Some_POSIX_Threads_and_Synchronization_examples_in_Odin

Some_POSIX_Threads_and_Synchronization_examples_in_Odin

9281467library

A comprehensive collection of 50 examples teaching multithreaded programming with POSIX threads in Odin in Linux.

No license · updated 5 months ago

Some POSIX Threads and Synchronization examples in Odin

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.

License

MIT License

Overview

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

Running Examples

Each example can be run independently:

odin run 01_hello_thread.odin -file

To run all tests:

for f in *.odin; do
    echo "Testing $f..."
    odin run "$f" -file
done

Part 1: Thread Basics (Examples 01-08)

Basic 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 execution
  • thread.join() - Wait for thread completion
  • thread.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_index for thread identification

Thread Priority and Yielding

Thread priority levels (requires root on Linux) and manual yielding.

API Covered:

  • thread.Thread.Priority enum (.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)

Part 2: Basic Synchronization (Examples 09-16)

Introduction to Mutexes

Mutual exclusion for protecting shared data.

API Covered:

  • sync.Mutex - Basic mutex type (zero-initialized)
  • sync.mutex_lock() - Acquire lock
  • sync.mutex_unlock() - Release lock

RAII-Style Mutex Guards

Automatic lock release using scoped guards.

API Covered:

  • sync.guard() - Scoped lock guard
  • sync.Mutex_Guard - Guard type
  • defer pattern 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 mutex
  • sync.shared_lock() / sync.shared_unlock() - Reader locks
  • sync.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

Part 3: Advanced Synchronization (Examples 17-24)

Introduction to Condition Variables

Signaling between threads for coordination.

API Covered:

  • sync.Cond - Condition variable
  • sync.cond_wait() - Wait for signal
  • sync.cond_signal() - Wake one waiter
  • sync.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 type
  • sync.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 type
  • sync.barrier_init() - Initialize with party count
  • sync.barrier_wait() - Wait at barrier

Wait Groups

Waiting for a collection of tasks to complete.

API Covered:

  • sync.Wait_Group - Wait group type
  • sync.wait_group_add() - Add tasks to wait for
  • sync.wait_group_done() - Mark task complete
  • sync.wait_group_wait() - Wait for all tasks

One-Time Initialization

Ensuring code runs exactly once, regardless of thread count.

API Covered:

  • sync.Once - Once type
  • sync.once_do() - Execute exactly once

Part 4: Classic Problems (Examples 25-30)

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

Part 5: Thread Pools (Examples 31-36)

Introduction to Thread Pools

Reusing threads for multiple tasks.

API Covered:

  • thread.Pool - Built-in thread pool
  • thread.pool_init() - Initialize pool
  • thread.pool_start() - Start worker threads
  • thread.pool_finish() - Wait for completion
  • thread.pool_destroy() - Cleanup

Submitting Multiple Tasks

Adding work to the thread pool.

API Covered:

  • thread.pool_add_task() - Submit work
  • thread.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

Part 6: Advanced Patterns (Examples 37-50)

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 read
  • sync.atomic_store() - Atomic write
  • sync.atomic_add() - Atomic add
  • sync.atomic_exchange() - Atomic swap
  • sync.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

API Quick Reference

Thread Management (core:thread)

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

Thread Pool (core:thread)

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

Synchronization (core:sync)

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

Mutex Operations

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

Read-Write Mutex Operations

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

Condition Variable Operations

Function Description
sync.cond_wait(&c, &m) Wait for signal
sync.cond_signal(&c) Wake one waiter
sync.cond_broadcast(&c) Wake all waiters

Semaphore Operations

Function Description
sync.sema_post(&s) Increment (signal)
sync.sema_wait(&s) Decrement (wait)

Barrier Operations

Function Description
sync.barrier_init(&b, count) Initialize with party count
sync.barrier_wait(&b) Wait at barrier

Wait Group Operations

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

Atomic Operations

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

Learning Path

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.


Acknowledgments