CodingHowTo

Debounce/Throttle a Function Call in Pure C++

Debounce/Throttle a Function Call in Pure C++

What is Debouncing?

Debouncing ensures that a function is not called repeatedly in quick succession. Instead, it waits for a specified amount of time to see if the event fires again. If the event does not fire within this period, the function executes.

What is Throttling?

Throttling limits the rate at which a function can be executed. It ensures that the function is called no more than once within a specified time interval, regardless of how many times the event triggers.

Debouncing Implementation


#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

template<typename Func, typename... Args>
std::function debounce(Func func, std::chrono::milliseconds wait_time, Args... args) {
    std::atomic<bool> should_call = false;
    std::thread t([&func, &should_call, args..., wait_time]() {
        while (true) {
            if (should_call.load()) {
                should_call.store(false);
                func(args...);
                std::this_thread::sleep_for(wait_time);
            }
        }
    });
    t.detach();
    return [&should_call]() { should_call.store(true); };
}

void printMessage(const std::string& message) {
    std::cout << "Message: " << message << std::endl;
}

int main() {
    auto debouncedPrint = debounce(printMessage, std::chrono::milliseconds(500), "Hello, Debounce!");
    
    for (int i = 0; i < 10; ++i) {
        debouncedPrint();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

Throttling Implementation


#include <iostream>
#include <chrono>
#include <thread>
#include <functional>

template<typename Func, typename... Args>
std::function throttle(Func func, std::chrono::milliseconds wait_time, Args... args) {
    std::atomic<bool> can_call = true;
    return [&func, &can_call, args..., wait_time]() {
        if (can_call.load()) {
            can_call.store(false);
            func(args...);
            std::thread t([&can_call, wait_time]() {
                std::this_thread::sleep_for(wait_time);
                can_call.store(true);
            });
            t.detach();
        }
    };
}

void printMessage(const std::string& message) {
    std::cout << "Message: " << message << std::endl;
}

int main() {
    auto throttledPrint = throttle(printMessage, std::chrono::milliseconds(500), "Hello, Throttle!");
    
    for (int i = 0; i < 10; ++i) {
        throttledPrint();
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    return 0;
}

Conclusion

Debouncing and throttling are powerful techniques for controlling the execution frequency of functions in C++. By using these methods, you can prevent your application from being overwhelmed by rapid events and ensure that your functions are executed at a controlled rate. The provided implementations demonstrate how to achieve this using basic threading and atomic operations.