Condition Thread type

The fossil_threads_cond library provides a cross-platform abstraction for condition variables. Condition variables allow threads to wait for certain conditions while atomically releasing a mutex. This is useful for signaling between producer-consumer threads or coordinating multiple threads. The C++ RAII wrapper fossil::threads::Cond ensures safe initialization, disposal, and exception-aware operations.

HEADER REFERENCE #

#ifndef FOSSIL_THREADS_COND_H
#define FOSSIL_THREADS_COND_H

#include "mutex.h"

#ifdef __cplusplus
extern "C"
{
#endif

#if defined(_WIN32) && defined(FOSSIL_THREADS_BUILD_DLL)
#  define FOSSIL_THREADS_API __declspec(dllexport)
#elif defined(_WIN32) && defined(FOSSIL_THREADS_USE_DLL)
#  define FOSSIL_THREADS_API __declspec(dllimport)
#else
#  define FOSSIL_THREADS_API
#endif

/* ---------- Types ---------- */

typedef struct fossil_threads_cond {
    void *handle;  /* CONDITION_VARIABLE* on Win, pthread_cond_t* on POSIX */
    int   valid;
} fossil_threads_cond_t;

/* ---------- Lifecycle ---------- */

// *****************************************************************************
// Function prototypes
// *****************************************************************************

/**
 * @brief Initialize a condition variable.
 *
 * This function initializes the given condition variable structure.
 * Must be called before using the condition variable.
 *
 * @param c Pointer to the condition variable to initialize.
 * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
 */
FOSSIL_THREADS_API int fossil_threads_cond_init(fossil_threads_cond_t *c);

/**
 * @brief Dispose of a condition variable.
 *
 * This function releases any resources associated with the condition variable.
 * After calling this, the condition variable must not be used unless re-initialized.
 *
 * @param c Pointer to the condition variable to dispose.
 */
FOSSIL_THREADS_API void fossil_threads_cond_dispose(fossil_threads_cond_t *c);

/* ---------- Wait / signal ---------- */

/**
 * @brief Wait on a condition variable.
 *
 * Atomically unlocks the given mutex and waits for the condition variable to be signaled.
 * When the wait is over, the mutex is re-locked before returning.
 *
 * @param c Pointer to the condition variable.
 * @param m Pointer to the mutex (must be locked by the calling thread).
 * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
 */
FOSSIL_THREADS_API int fossil_threads_cond_wait(
    fossil_threads_cond_t *c,
    fossil_threads_mutex_t *m
);

/**
 * @brief Wait on a condition variable with a timeout.
 *
 * Atomically unlocks the given mutex and waits for the condition variable to be signaled
 * or for the specified timeout (in milliseconds) to elapse. When the wait is over,
 * the mutex is re-locked before returning.
 *
 * @param c Pointer to the condition variable.
 * @param m Pointer to the mutex (must be locked by the calling thread).
 * @param ms Timeout in milliseconds.
 * @return FOSSIL_THREADS_COND_OK if signaled, FOSSIL_THREADS_COND_ETIMEDOUT if timeout,
 *         or error code on failure.
 */
FOSSIL_THREADS_API int fossil_threads_cond_timedwait(
    fossil_threads_cond_t *c,
    fossil_threads_mutex_t *m,
    unsigned int ms
);

/**
 * @brief Wake one thread waiting on the condition variable.
 *
 * Signals the condition variable, waking up one waiting thread (if any).
 *
 * @param c Pointer to the condition variable.
 * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
 */
FOSSIL_THREADS_API int fossil_threads_cond_signal(fossil_threads_cond_t *c);

/**
 * @brief Wake all threads waiting on the condition variable.
 *
 * Broadcasts to the condition variable, waking up all waiting threads.
 *
 * @param c Pointer to the condition variable.
 * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
 */
FOSSIL_THREADS_API int fossil_threads_cond_broadcast(fossil_threads_cond_t *c);

/* Error codes */
enum {
    FOSSIL_THREADS_COND_OK        = 0,
    FOSSIL_THREADS_COND_EINVAL    = 22,
    FOSSIL_THREADS_COND_ETIMEDOUT = 110,
    FOSSIL_THREADS_COND_EINTERNAL = 199
};

#ifdef __cplusplus
}
#include <stdexcept>
#include <vector>
#include <string>

namespace fossil {

namespace threads {

    /**
     * @brief C++ RAII wrapper for fossil_threads_cond_t.
     *
     * This class provides a safe, exception-aware C++ interface for
     * managing condition variables using the Fossil Threads API.
     * It disables copy construction and assignment to prevent
     * accidental resource duplication.
     */
    class Cond {
    public:
        /**
         * @brief Constructs and initializes the condition variable.
         *
         * Throws std::runtime_error if initialization fails.
         */
        Cond() {
            int rc = fossil_threads_cond_init(&cond_);
            if (rc != FOSSIL_THREADS_COND_OK) {
                throw std::runtime_error("Failed to initialize condition variable");
            }
        }

        /**
         * @brief Destructor. Disposes of the condition variable.
         *
         * Ensures resources are released when the object goes out of scope.
         */
        ~Cond() {
            fossil_threads_cond_dispose(&cond_);
        }

        /**
         * @brief Deleted copy constructor.
         *
         * Prevents copying of the condition variable wrapper.
         */
        Cond(const Cond&) = delete;

        /**
         * @brief Deleted copy assignment operator.
         *
         * Prevents assignment of the condition variable wrapper.
         */
        Cond& operator=(const Cond&) = delete;

        /**
         * @brief Waits on the condition variable.
         *
         * Atomically unlocks the given mutex and waits for the condition variable to be signaled.
         * The mutex is re-locked before returning.
         *
         * @param mutex Pointer to the mutex (must be locked by the calling thread).
         * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
         */
        int wait(fossil_threads_mutex_t *mutex) {
            return fossil_threads_cond_wait(&cond_, mutex);
        }

        /**
         * @brief Waits on the condition variable with a timeout.
         *
         * Atomically unlocks the given mutex and waits for the condition variable to be signaled
         * or for the specified timeout (in milliseconds) to elapse.
         * The mutex is re-locked before returning.
         *
         * @param mutex Pointer to the mutex (must be locked by the calling thread).
         * @param ms Timeout in milliseconds.
         * @return FOSSIL_THREADS_COND_OK if signaled, FOSSIL_THREADS_COND_ETIMEDOUT if timeout,
         *         or error code on failure.
         */
        int timed_wait(fossil_threads_mutex_t *mutex, unsigned int ms) {
            return fossil_threads_cond_timedwait(&cond_, mutex, ms);
        }

        /**
         * @brief Wakes one thread waiting on the condition variable.
         *
         * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
         */
        int signal() {
            return fossil_threads_cond_signal(&cond_);
        }

        /**
         * @brief Wakes all threads waiting on the condition variable.
         *
         * @return FOSSIL_THREADS_COND_OK on success, or error code on failure.
         */
        int broadcast() {
            return fossil_threads_cond_broadcast(&cond_);
        }

        /**
         * @brief Returns a pointer to the underlying native handle.
         *
         * @return Pointer to the fossil_threads_cond_t structure.
         */
        fossil_threads_cond_t* native_handle() { return &cond_; }

    private:
        fossil_threads_cond_t cond_; /**< The underlying condition variable structure. */
    };

} // namespace threads

} // namespace fossil

#endif

#endif /* FOSSIL_THREADS_COND_H */

SAMPLE CODE C #

#include "fossil/threads/cond.h"
#include "fossil/threads/mutex.h"
#include <stdio.h>
#include <threads.h>

fossil_threads_mutex_t mtx;
fossil_threads_cond_t cond;
int ready = 0;

int worker(void *arg) {
    fossil_threads_mutex_lock(&mtx);
    while (!ready) {
        fossil_threads_cond_wait(&cond, &mtx);
    }
    printf("Worker thread running!\n");
    fossil_threads_mutex_unlock(&mtx);
    return 0;
}

int main() {
    fossil_threads_mutex_init(&mtx);
    fossil_threads_cond_init(&cond);

    thrd_t t;
    thrd_create(&t, worker, NULL);

    fossil_threads_mutex_lock(&mtx);
    ready = 1;
    fossil_threads_cond_signal(&cond);
    fossil_threads_mutex_unlock(&mtx);

    thrd_join(t, NULL);

    fossil_threads_cond_dispose(&cond);
    fossil_threads_mutex_dispose(&mtx);
    return 0;
}

SAMPLE CODE C++ #

#include "fossil/threads/cond.h"
#include "fossil/threads/mutex.h"
#include <iostream>
#include <thread>
#include <vector>

fossil::threads::Mutex mtx;
fossil::threads::Cond cond;
bool ready = false;

void worker(int id) {
    mtx.lock();
    while (!ready) {
        cond.wait(mtx.native_handle());
    }
    std::cout << "Thread " << id << " running!\n";
    mtx.unlock();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back(worker, i);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    mtx.lock();
    ready = true;
    cond.broadcast();
    mtx.unlock();

    for (auto &t : threads) t.join();
}

What are your feelings

Updated on August 21, 2025