Skip to the content.

asynchrony : Asynchrony support library

CodeQL Build Status

Getting started

NOTE We are going to track VS 2022 and make full use of C++20 facilities and the API is subject to change.

API

Utility Description
siddiqsoft::simple_worker Provides for a single thread with an internal deque.
You’d use this to immediately make any “long” task asynchronous.
Use instead of std::async.
Just register your callback/lambda and you’re done. No need to worry about waiting for the result (no worry about futures or waiting on them).
Your declared callback will be invoked!
siddiqsoft::simple_pool Implements an array of threads backed with a single deque. Each thread waits for and processes the next available item from the single deque.
siddiqsoft::roundrobin_pool Implements an vector of basic_workers (each worker has its independent queue therefore minimizing contention time).
The queue method implements a running counter based round-robin feeder.
siddiqsoft::periodic_worker Provides a facility where you can have your function/lambda invoked at a given periodic rate (in microseconds).

siddiqsoft::simple_worker

Provides for a single thread with an internal deque.

You’d use this to immediately make any “long” task asynchronous where you do not need std::future and std::async.

Just register your callback/lambda and you’re done. No need to worry about waiting for the result (no worry about futures or waiting on them).

    template <typename T, uint16_t Pri = 0>
        requires ((Pri >= -10) && (Pri <= 10)) &&
                 std::move_constructible<T>
    struct simple_worker
    {
        simple_worker(simple_worker&) = delete;
        auto operator=(simple_worker&) = delete;

        ~simple_worker();
        simple_worker(simple_worker&& src) noexcept;
        simple_worker(std::function<void(T&)> c) noexcept;

        void queue(T&& item);

        nlohmann::json toJson();

    private:
        std::deque<T>                items {};
        std::shared_mutex            items_mutex {};
        std::counting_semaphore<512> signal {0};
        std::chrono::milliseconds    signalWaitInterval {1500};
        std::function<void(T&)>      callback;
        std::jthread                 processor;
    };

siddiqsoft::simple_pool

Implements an array of threads backed with a single deque. Each thread waits for and processes the next available item from the single deque.

    template <typename T, uint16_t N = 0>
        requires std::move_constructible<T>
    struct simple_pool
    {
        simple_pool(simple_pool&&)            = delete;
        simple_pool& operator=(simple_pool&&) = delete;
        simple_pool(simple_pool&)             = delete;
        simple_pool& operator=(simple_pool&)  = delete;

        ~simple_pool();
        simple_pool(std::function<void(T&&)> c);
        
        void queue(T&& item);

        nlohmann::json toJson();

    private:
        std::atomic_uint64_t         queueCounter {0};
        std::vector<std::jthread>    workers {};
        std::function<void(T&&)>     callback;
        std::counting_semaphore<512> signal {0};
        std::deque<T>                items {};
        std::shared_mutex            items_mutex;
        std::chrono::milliseconds    signalWaitInterval {1500};
    };

siddiqsoft::roundrobin_pool

Implements an vector of basic_workers (each worker has its independent queue therefore minimizing contention time).
The queue method implements a running counter based round-robin feeder.

    template <typename T, uint16_t N = 0>
        requires std::move_constructible<T>
    struct roundrobin_pool
    {
        roundrobin_pool(roundrobin_pool&&) = delete;
        auto operator=(roundrobin_pool&&)  = delete;
        roundrobin_pool(roundrobin_pool&)  = delete;
        auto operator=(roundrobin_pool&)   = delete;

        roundrobin_pool(std::function<void(T&&)> c);

        void queue(T&& item);

        nlohmann::json toJson();

    private:
        std::atomic_uint64_t          queueCounter {0};
        std::vector<simple_worker<T>> workers {};
        uint64_t                      workersSize {};
        constexpr size_t              nextWorkerIndex()
    };

siddiqsoft::periodic_worker

Provides a facility where you can have your function/lambda invoked at a given periodic rate (in microseconds).

You’d instantiate this class with your lambda and period in microseconds.

    template <uint16_t Pri = 0>
        requires ((Pri >= -10) && (Pri <= 10))
    struct periodic_worker
    {
        periodic_worker(periodic_worker&)  = delete;
        auto& operator=(periodic_worker&)  = delete;
        periodic_worker(periodic_worker&&) = delete;
        auto& operator=(periodic_worker&&) = delete;

        ~periodic_worker();
        periodic_worker(std::function<void()> c, std::chrono::microseconds) noexcept;

        nlohmann::json toJson();

    private:
        uint64_t                    invokeCounter{0};
        std::chrono::microseconds   invokePeriod {};
        std::counting_semaphore<1>  signal {0};
        std::function<void()>       callback;
        std::jthread                processor;
    };