Mutex Thread type

The fossil_threads_mutex library provides a cross-platform abstraction for mutual exclusion. It allows threads to safely synchronize access to shared resources. The library supports blocking locks, non-blocking try-locks, and RAII-style management in C++ via the Mutex class. This ensures safe initialization, destruction, and exception-safe locking/unlocking in multithreaded code.

HEADER REFERENCE #

#ifndef FOSSIL_THREADS_MUTEX_H
#define FOSSIL_THREADS_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_mutex {
    void *handle;   /* CRITICAL_SECTION* or pthread_mutex_t* */
    int   valid;    /* 1 if initialized */
} fossil_threads_mutex_t;

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

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

/* 
 * Initializes a mutex object.
 * 
 * Parameters:
 *   m - Pointer to a fossil_threads_mutex_t structure to initialize.
 * 
 * Returns:
 *   0 on success, or a nonzero error code on failure.
 * 
 * Notes:
 *   - The mutex must be disposed with fossil_threads_mutex_dispose when no longer needed.
 *   - The mutex is initially unlocked.
 */
FOSSIL_THREADS_API int fossil_threads_mutex_init(fossil_threads_mutex_t *m);

/* 
 * Disposes (destroys) a mutex object.
 * 
 * Parameters:
 *   m - Pointer to a fossil_threads_mutex_t structure to dispose.
 * 
 * Notes:
 *   - Safe to call on a zeroed or already-disposed mutex.
 *   - After disposal, the mutex should not be used unless re-initialized.
 */
FOSSIL_THREADS_API void fossil_threads_mutex_dispose(fossil_threads_mutex_t *m);

/* ---------- Locking ---------- */

/* 
 * Locks the mutex, blocking the calling thread until the mutex becomes available.
 * 
 * Parameters:
 *   m - Pointer to a fossil_threads_mutex_t structure to lock.
 * 
 * Returns:
 *   0 on success, or a nonzero error code on failure.
 * 
 * Notes:
 *   - If the mutex is already locked by another thread, this call will block.
 *   - Recursive locking is not supported unless implemented by the platform.
 */
FOSSIL_THREADS_API int fossil_threads_mutex_lock(fossil_threads_mutex_t *m);

/* 
 * Unlocks the mutex.
 * 
 * Parameters:
 *   m - Pointer to a fossil_threads_mutex_t structure to unlock.
 * 
 * Returns:
 *   0 on success, or a nonzero error code on failure.
 * 
 * Notes:
 *   - Only the thread that locked the mutex should unlock it.
 *   - Unlocking an unlocked mutex results in undefined behavior.
 */
FOSSIL_THREADS_API int fossil_threads_mutex_unlock(fossil_threads_mutex_t *m);

/* 
 * Attempts to lock the mutex without blocking.
 * 
 * Parameters:
 *   m - Pointer to a fossil_threads_mutex_t structure to try to lock.
 * 
 * Returns:
 *   0 if the mutex was successfully locked.
 *   FOSSIL_THREADS_MUTEX_EBUSY if the mutex is already locked.
 *   Other nonzero error code on failure.
 * 
 * Notes:
 *   - This function never blocks.
 *   - Useful for implementing timed or non-blocking synchronization.
 */
FOSSIL_THREADS_API int fossil_threads_mutex_trylock(fossil_threads_mutex_t *m);

/* Error codes */
enum {
    FOSSIL_THREADS_MUTEX_OK       = 0,
    FOSSIL_THREADS_MUTEX_EINVAL   = 22,  /* invalid arg */
    FOSSIL_THREADS_MUTEX_EBUSY    = 16,  /* already locked (trylock only) */
    FOSSIL_THREADS_MUTEX_EINTERNAL= 199
};

#ifdef __cplusplus
}
#include <stdexcept>
#include <utility>

namespace fossil {

namespace threads {

    class Mutex {
    public:
        /**
         * @brief Constructs a Mutex object and initializes the underlying mutex.
         * 
         * Throws std::runtime_error if initialization fails.
         */
        Mutex() {
            int rc = fossil_threads_mutex_init(&m_);
            if (rc != FOSSIL_THREADS_MUTEX_OK) {
            throw std::runtime_error("Failed to initialize mutex");
            }
        }

        /**
         * @brief Destroys the Mutex object and disposes the underlying mutex.
         */
        ~Mutex() {
            fossil_threads_mutex_dispose(&m_);
        }

        /**
         * @brief Locks the mutex, blocking if necessary.
         * 
         * Throws std::runtime_error if locking fails.
         */
        void lock() {
            int rc = fossil_threads_mutex_lock(&m_);
            if (rc != FOSSIL_THREADS_MUTEX_OK) {
            throw std::runtime_error("Failed to lock mutex");
            }
        }

        /**
         * @brief Unlocks the mutex.
         * 
         * Throws std::runtime_error if unlocking fails.
         */
        void unlock() {
            int rc = fossil_threads_mutex_unlock(&m_);
            if (rc != FOSSIL_THREADS_MUTEX_OK) {
            throw std::runtime_error("Failed to unlock mutex");
            }
        }

        /**
         * @brief Attempts to lock the mutex without blocking.
         * 
         * @return true if the mutex was successfully locked, false if it was already locked.
         * 
         * Throws std::runtime_error if an error occurs other than the mutex being busy.
         */
        bool try_lock() {
            int rc = fossil_threads_mutex_trylock(&m_);
            if (rc == FOSSIL_THREADS_MUTEX_OK) return true;
            if (rc == FOSSIL_THREADS_MUTEX_EBUSY) return false;
            throw std::runtime_error("Failed to try_lock mutex");
        }

        /**
         * @brief Deleted copy constructor to prevent copying.
         */
        Mutex(const Mutex&) = delete;

        /**
         * @brief Deleted copy assignment operator to prevent copying.
         */
        Mutex& operator=(const Mutex&) = delete;

    private:
        fossil_threads_mutex_t m_;
    };

} // namespace threads

} // namespace fossil

#endif

#endif /* FOSSIL_THREADS_MUTEX_H */

SAMPLE CODE C #

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

int main() {
    fossil_threads_mutex_t m;
    if (fossil_threads_mutex_init(&m) != 0) {
        printf("Failed to initialize mutex\n");
        return 1;
    }

    if (fossil_threads_mutex_lock(&m) != 0) {
        printf("Failed to lock mutex\n");
        fossil_threads_mutex_dispose(&m);
        return 1;
    }

    printf("Mutex locked!\n");

    fossil_threads_mutex_unlock(&m);
    printf("Mutex unlocked!\n");

    fossil_threads_mutex_dispose(&m);
    return 0;
}

SAMPLE CODE C++ #

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

fossil::threads::Mutex mtx;

void worker(int id) {
    mtx.lock();
    std::cout << "Thread " << id << " entered critical section.\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Thread " << id << " leaving critical section.\n";
    mtx.unlock();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(worker, i);
    }
    for (auto &t : threads) t.join();
}

What are your feelings

Updated on August 21, 2025