๐Ÿง  Problem: Implement a simple Promise/Future mechanism in C++, mimicking then()style chaining.


โœ… How We'll Solve It (in 4โ€“5 points):

  1. A Promise is an object that sets a value which will be available in the future.
  2. A Future is an object that retrieves the value once it's available โ€” possibly blocking if the value isnโ€™t ready yet.
  3. We'll support .then() chaining, which allows attaching callbacks that run when the value is set.
  4. We'll first implement a single-threaded version (synchronous), and then add a multithreaded version with std::mutex and std::condition_variable to handle concurrency.
  5. The multithreaded version ensures that callbacks run after the value is fulfilled, even across threads.

๐Ÿ”น Version 1: Simple Promise/Future (No Threads)


#include <iostream>
#include <functional>
#include <vector>

template <typename T>
class SimplePromise {
    T value;
    bool isSet = false;
    std::vector<std::function<void(T)>> callbacks;

public:
    void set_value(T val) {
        value = val;
        isSet = true;
        for (auto& cb : callbacks) {
            cb(value); // Call all registered callbacks
        }
    }

    void then(std::function<void(T)> cb) {
        if (isSet) {
            cb(value); // If already set, call immediately
        } else {
            callbacks.push_back(cb); // Otherwise, queue it
        }
    }
};

int main() {
    SimplePromise<int> p;
    p.then([](int val) {
        std::cout << "Callback 1: " << val << std::endl;
    });
    p.set_value(42); // Triggers callback
    p.then([](int val) {
        std::cout << "Callback 2: " << val << std::endl;
    }); // Runs immediately since value is already set
    return 0;
}


๐Ÿ”ธ Version 2: Promise/Future with Threads (Thread-safe)


#include <iostream>
#include <functional>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <chrono>

template <typename T>
class ThreadSafePromise {
private:
    T value;  // The promised value
    bool isSet = false;  // Flag to check if value has been set

    std::mutex mtx;  // Mutex to protect shared state
    std::condition_variable cv;  // To signal waiting threads
    std::vector<std::function<void(T)>> callbacks;  // List of attached callbacks

public:
    // Sets the value and executes any callbacks waiting
    void set_value(T val) {
        std::unique_lock<std::mutex> lock(mtx);  // ๐Ÿ”’ Critical Section Begins
        value = val;
        isSet = true;

        // Run all registered callbacks in separate threads
        for (auto& cb : callbacks) {
            std::thread(cb, value).detach();  // โœ… Detached = Fire and forget
        }

        // Notify any thread waiting on get()
        cv.notify_all();
        // ๐Ÿ”“ Critical Section Ends when lock goes out of scope
    }

    // Registers a callback to be executed when the value is set
    void then(std::function<void(T)> cb) {
        std::unique_lock<std::mutex> lock(mtx);  // ๐Ÿ”’ Critical Section Begins
        if (isSet) {
            // If already set, immediately run callback in new thread
            std::thread(cb, value).detach();
        } else {
            // Else store the callback for later execution
            callbacks.push_back(cb);
        }
        // ๐Ÿ”“ Critical Section Ends
    }

    // Blocks the caller until value is available and returns it
    T get() {
        std::unique_lock<std::mutex> lock(mtx);  // ๐Ÿ”’ Critical Section Begins
        cv.wait(lock, [&] { return isSet; });  // Wait until isSet is true
        return value;
        // ๐Ÿ”“ Critical Section Ends
    }
};
int main() {
    ThreadSafePromise<int> promise;

    // Thread 1: Registers a callback BEFORE the value is set
    std::thread t1([&]() {
        promise.then([](int val) {
            std::cout << "[Callback 1] Got value: " << val << std::endl;
        });
    });

    // Thread 2: Sets the value after some delay
    std::thread t2([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        promise.set_value(99);  // Triggers Callback 1
    });

    // Thread 3: Registers a callback AFTER the value is already set
    std::thread t3([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        promise.then([](int val) {
            std::cout << "[Callback 2] Got value (late): " << val << std::endl;
        });
    });

    t1.join();
    t2.join();
    t3.join();

    return 0;
}


๐Ÿงช Sample main() to demonstrate how it works


int main() {
    ThreadSafePromise<int> promise;

    // Thread 1: Registers a callback BEFORE the value is set
    std::thread t1([&]() {
        promise.then([](int val) {
            std::cout << "[Callback 1] Got value: " << val << std::endl;
        });
    });

    // Thread 2: Sets the value after some delay
    std::thread t2([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        promise.set_value(99);  // Triggers Callback 1
    });

    // Thread 3: Registers a callback AFTER the value is already set
    std::thread t3([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        promise.then([](int val) {
            std::cout << "[Callback 2] Got value (late): " << val << std::endl;
        });
    });

    t1.join();
    t2.join();
    t3.join();

    return 0;
}


๐Ÿ” What are the Critical Sections?

๐Ÿ” Critical Section Purpose
set_value() Sets shared state value and isSet, and safely runs callbacks
then() Checks isSet and safely appends or runs callback
get() Waits on condition variable until value is available