zthread.h brings portable multithreading to C, with C++ native-like support. It abstracts Win32 and POSIX threads into a unified, type-safe API, allowing you to write concurrent code that runs natively on Windows, Linux, and macOS without complex build configurations.
It is designed to be zero friction - handling the differences between pthreads and CreateThread internally so you can focus on your logic.
- Cross-Platform: Native backends for Win32 and POSIX (pthread). No middleware or heavy runtimes.
- Type-Safe Creation: Macros automatically handle
void*casting, allowing typed function arguments. - Unified Primitives: Consistent API for Mutexes and Condition Variables across all OSs.
- Strict Compliance: Optional
ZTHREAD_WRAPmacro for pedantic standard compliance (avoids function pointer casting). - Zero Dependencies: Uses only standard system headers.
- ZDK Integration: Respects global ZDK memory allocators (
Z_MALLOC) for internal allocations. - Single Header: Drop-in and use. No linking arguments (
-lpthreadis strictly optional on modern GCC/Clang, but recommended).
- Copy
zthread.hto your project's include folder. - Include it where needed.
#define ZTHREAD_IMPLEMENTATION // Define in ONE .c file.
#include "zthread.h"Optional Short Macros: To enable clean keywords like
thread_create,mutex_lock, andcond_wait, defineZTHREAD_SHORT_NAMESbefore including the header.
#define ZTHREAD_SHORT_NAMES
#include "zthread.h"Instead of casting void* arguments manually, zthread.h lets you pass typed pointers directly.
void worker(int *counter)
{
(*counter)++;
printf("Counter updated to: %d\n", *counter);
}
int main(void)
{
zthread_t t;
int count = 0;
// Macro automatically casts 'worker' and '&count'.
if (zthread_create(&t, worker, &count) == Z_OK)
{
zthread_join(t);
}
return 0;
}Protect shared resources using zmutex. The API is unified for Windows and Linux.
zmutex_t lock;
int shared_resource = 0;
void unsafe_increment()
{
zmutex_lock(&lock);
shared_resource++; // Critical section.
zmutex_unlock(&lock);
}
int main(void)
{
zmutex_init(&lock);
// ... spawn threads ...
zmutex_destroy(&lock);
}Wait for signals efficiently without busy loops.
zmutex_t m;
zcond_t ready;
bool data_is_ready = false;
void consumer()
{
zmutex_lock(&m);
while (!data_is_ready)
{
// Releases lock and sleeps until signaled.
zcond_wait(&ready, &m);
}
process_data();
zmutex_unlock(&m);
}
void producer()
{
zmutex_lock(&m);
data_is_ready = true;
zcond_signal(&ready); // Wake up the consumer
zmutex_unlock(&m);
}While casting function pointers is common in C, strict standard compliance technically forbids casting void (*)(T*) to void (*)(void*). If you need 100% compliance, use the wrapper generator.
// Generates a strictly compliant void* proxy function.
ZTHREAD_WRAP(heavy_task, Config*, cfg)
{
printf("Processing %s\n", cfg->name);
}
int main(void)
{
Config c = { "Job 1" };
zthread_t t;
// Pass the safe wrapper to the thread creator.
zthread_create(&t, heavy_task, &c);
}zthread.h allocates a tiny wrapper struct for every thread to bridge the OS entry point types. By default, it uses malloc. You can override this globally or locally. You can use zalloc.h.
// Override for just zthread
#define ZTHREAD_MALLOC(sz) my_custom_alloc(sz)
#define ZTHREAD_FREE(ptr) my_custom_free(ptr)
#include "zthread.h"Thread Management
| Function/Macro | Description |
|---|---|
zthread_create(t, fn, arg) |
Spawns a new thread. Returns Z_OK on success. |
zthread_join(t) |
Blocks until the thread t finishes execution. |
zthread_detach(t) |
Detaches the thread (it cleans up automatically on exit). |
zthread_sleep(ms) |
Sleeps the current thread for ms milliseconds. |
ZTHREAD_WRAP(name, T, v) |
Defines a type-safe wrapper implementation block. |
Synchronization
| Function | Description |
|---|---|
zmutex_init(m) |
Initializes a mutex. |
zmutex_lock(m) |
Acquires the lock (blocks if taken). |
zmutex_unlock(m) |
Releases the lock. |
zmutex_destroy(m) |
Frees mutex resources. |
Condition Variables
| Function | Description |
|---|---|
zcond_init(c) |
Initializes a condition variable. |
zcond_wait(c, m) |
Atomically unlocks mutex m and waits for signal on c. |
zcond_signal(c) |
Wakes up one waiting thread. |
zcond_broadcast(c) |
Wakes up all waiting threads. |
zcond_destroy(c) |
Frees condition variable resources. |
The C++ wrapper lives in the z_thread namespace. It strictly adheres to RAII principles and delegates all logic to the underlying C implementation.
Constructors & Management
| Method | Description |
|---|---|
thread() |
Default constructor (empty/inactive). |
thread(Func&& f, Args&&...) |
Spawns a new thread executing f with arguments. |
~thread() |
Destructor. Terminates if thread is still joinable. |
operator= |
Move assignment operator. |
Control & State
| Method | Description |
|---|---|
join() |
Blocks until the thread finishes execution. |
detach() |
Detaches the thread (runs independently). |
joinable_state() |
Returns true if the thread is active and joinable. |
native_handle() |
Returns the underlying zthread_t handle. |
sleep(ms) |
Static. Sleeps the current thread for ms milliseconds. |
Management & Locking
| Method | Description |
|---|---|
mutex() |
Default constructor. Initializes the mutex. |
~mutex() |
Destructor. Destroys the mutex resources. |
lock() |
Acquires the lock (blocks if already taken). |
unlock() |
Releases the lock. |
native_handle() |
Returns pointer to underlying zmutex_t. |
RAII Locking
| Method | Description |
|---|---|
lock_guard(mutex& m) |
Acquires lock on construction. |
~lock_guard() |
Releases lock on destruction. |
Waiting & Signaling
| Method | Description |
|---|---|
cond() |
Default constructor. Initializes the condition variable. |
~cond() |
Destructor. Destroys the condition variable. |
wait(mutex& m) |
Atomically unlocks m and waits for a signal. Relocks on return. |
signal() |
Wakes up one waiting thread. |
broadcast() |
Wakes up all waiting threads. |
native_handle() |
Returns pointer to underlying zcond_t. |
| Define | Effect |
|---|---|
ZTHREAD_IMPLEMENTATION |
Enables the implementation (define in one .c file). |
ZTHREAD_SHORT_NAMES |
Enables short aliases (thread_create, mutex_lock, etc.). |
ZTHREAD_MALLOC |
Override memory allocation (Default: stdlib.h malloc). |
ZTHREAD_FREE |
Override memory free (Default: stdlib.h free). |