Go-Flavored Concurrency in C
4 hours ago
- #concurrency
- #Go
- #pthreads
- Go's concurrency model is popular for its lightweight goroutines, channels, and efficient runtime scheduler, but replicating it in C using only POSIX threads presents trade-offs.
- Solod (So) implements a concurrency stack based on pthread primitives: sync.Mutex and sync.Cond wrap pthread_mutex_t and pthread_cond_t, providing basic synchronization.
- Atomic operations in So map directly to C's __atomic built-ins, matching Go's performance for load, store, and compare-and-swap operations without pthread overhead.
- So's conc.Pool uses a fixed number of worker threads with a shared task queue, built with mutexes and condition variables, suitable for coarse-grained workloads but not for thousands of blocked tasks like goroutines.
- Channels in So (conc.Chan[T]) support buffered and unbuffered modes, using mutexes and condition variables for synchronization, with performance close to Go for pooled tasks but slower for fine-grained hand-offs due to kernel wakeup costs.
- Benchmarks show So's pthread-based concurrency is competitive for uncontended locks and atomic operations, but condition variables and channels are significantly slower when threads block, with up to 23x slower unbuffered channel transfers.
- Design decisions include using pthreads instead of fibers for simplicity, keeping concurrency in the standard library for explicit allocations and flexibility, and providing timeouts instead of select for channel operations.
- The approach offers simplicity and performance close to Go for coarse-grained workloads but cannot match Go's efficiency for fine-grained concurrency due to the overhead of kernel thread management.