Home > front end >  Run function every 5s inside loop running every second
Run function every 5s inside loop running every second

Time:10-26

I need to run my function MyFunc() every five seconds using the parameters in the code (i.e. minimum code changes).

There are two parameters in the code: ts and std::chrono::system_clock::now()

What do I write in condition so that I can run my function at the interval?

auto ts = std::chrono::system_clock::now()   std::chrono::seconds(1);

do {
    // 1s timer
    if ( ts <= std::chrono::system_clock::now()) {

        // ... doing some work

        // here I need to start MyFunc() every 5s
        if (condition) {
            MyFunc();
        }

        ts  = std::chrono::seconds(1);
    }

} while (isWork);

CodePudding user response:

The way in my mind is to check whether the time passed is greater than 5 seconds. You could do something similar to this, where there is a separate variable to keep track of 5 seconds after the last time that the function was run:

auto ts = std::chrono::system_clock::now()   std::chrono::seconds(1);
auto fiveseconds = std::chrono::system_clock::now()   std::chrono::seconds(5);

do {
    // 1s timer
    if ( ts <= std::chrono::system_clock::now()) {

        // ... doing some work

        // here I need to start MyFunc() every 5s
        if (fiveseconds <= std::chrono::system_clock::now()) {
            MyFunc();
            fiveseconds = std::chrono::system_clock::now()   std::chrono::seconds(5);
        }

        ts  = std::chrono::seconds(1);
    }

} while (isWork);

Note that this may not run it exactly every five seconds, just about when it runs the once-a-second loop, and then checks if it has been over five seconds.

CodePudding user response:

This is how I would do it. I don't use sleep because that could delay shutdown a lot. Instead I use a condition variable to wait at most 5 seconds to check if a stop condition is triggered, but returns immediately if the stop condition is triggered. This make reaction to your stopping much more responsive.

By using std::async the main thread keeps free for other things if needed. Also this will not be a busy wait loop (low CPU usage) to check if time has passed.

Live demo here (with 1s loop time) https://onlinegdb.com/qYA_IBqFQ

Some background material:

https://www.learncpp.com/cpp-tutorial/introduction-to-lambdas-anonymous-functions/ https://thispointer.com/c11-multithreading-part-9-stdasync-tutorial-example/ https://en.cppreference.com/w/cpp/thread/mutex https://en.cppreference.com/w/cpp/thread/condition_variable (despite its name it is more of an interthread signal then a variable)

#include <future>
#include <chrono>
#include <thread>
#include <iostream>

using namespace std::chrono_literals;

int main()
{
    bool keep_running{ true };              // a flag indicating if you want to keep processing
    std::condition_variable signal;         // a signal between two threads that (maybe) keep_running has changed value
    std::mutex mtx;                         // a mutex to use with flag/signal. (mutexes are often needed when more then 1 thread is involved)

    std::cout << "press return to stop\n";

    char output_char = 'x';

    // launch a lambda function in a thread
    // pass the boolean keep running
    // [&] captures : output_char, mtx, signal and keep_running by reference
    // making them available in the background thread.
    // (Make sure these variables 'live' longer then the duration of the thread
    // thats why the future.get() later is important).
    auto future = std::async(std::launch::async, [&]
        {
            while (keep_running)
            {
                std::cout << output_char;   // show we are looping

                // get a lock, this is needed for safe waiting on the signal
                std::unique_lock<std::mutex>  lock{ mtx };

                // I tend to never use sleep, but use a condition variable to
                // be able to respond faster
                // wait_for waits for 5s OR until keep_runnning is false
                signal.wait_for(lock, 5s, [&] { return !keep_running; }); 
            }
        });

    auto c = getchar();
    std::cout << "stopping\n";

    // update keep_running and condition variable in a lock too
    {
        std::unique_lock<std::mutex> lock{ mtx };
        keep_running = false;
        signal.notify_one();
    }

    future.get(); // wait for thread to have stopped.
    std::cout << "stopped\n";

    return 0;
}
  • Related