3

The following code prints the argument passed to the function foo in every 5 second interval.

function foo(arg) {
  console.log(arg);
}

setInterval(() => foo(5), 5000);

I found this answer: https://stackoverflow.com/a/43373364/13798537 that calls a function at periodic interval, but I couldn't figure out how to call a function at periodic interval that takes argument as shown in the javascript code.

Is there an equivalent to the javascript code in C++?
Thanks.

suravshrestha
  • 329
  • 1
  • 5
  • 14
  • There isn't one. JavaScript has a built-in "event loop" but C++ does not. You have to write your own: `while(program is running) {wait for the time when something is supposed to happen; make the thing happen;}` – user253751 May 13 '22 at 08:58

1 Answers1

3

You actually can get pretty close to the javascript syntax:

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

using cancel_token_t = std::atomic_bool;

template<typename Fnc>
void set_interval(Fnc fun, std::chrono::steady_clock::duration interval,
                  std::shared_ptr<cancel_token_t> cancel_token=nullptr)
{
  std::thread([fun=std::move(fun), interval, tok=std::move(cancel_token)]()
  { 
    while (!tok || !*tok) // Call until token becomes true (if it is set)
    { 
      auto next = std::chrono::steady_clock::now() + interval;
      fun();
      std::this_thread::sleep_until(next);
    }
  }).detach();
}

void foo(int n)
{
  std::cout << "Hello from foo("<<n<<")!\n";
}

int main()
{
using namespace std::chrono_literals;
  auto cancel = std::make_shared<cancel_token_t>(false);
  int x = 2;
  // Ordinary rules for lambda capture apply so be careful 
  // about lifetime if captured by reference.
  set_interval([x]{foo(5+x);}, 1000ms, cancel);
  //set_interval([x]{foo(5+x);}, 1000ms); // Without token, runs until main exits.
  std::this_thread::sleep_for(3s);
  *cancel=true;
}

I've modified the linked question and added a cancellation token which cooperatively cancels the thread when set to true. There is of course some delay between *cancel=true and the loop check.

I made the token optional, if not used, the thread will die when process exits after return from main. Although this is not guaranteed by C++, it works on common platforms.

std::chrono enforces correct usage of time units.

Feel free to ask if I should explain anything.

Quimby
  • 17,735
  • 4
  • 35
  • 55
  • Is the _logical or_ intended in the `while` condition? – paolo May 13 '22 at 08:50
  • @paolo Yes, indeed it is, nice catch, thanks! – Quimby May 13 '22 at 08:51
  • For cancellable threads on C++20 meet the new `std::jthread`. https://en.cppreference.com/w/cpp/thread/jthread/request_stop – Red.Wave May 13 '22 at 09:01
  • @Quimby , what can I do if I need to pass an object reference instead of an integer? – suravshrestha May 13 '22 at 09:40
  • @suravshrestha Just change the type to the desired one, it will work, but you have to be careful about lifetime of that object. Please edit your question with desired usage, can be in pseudo-code, just so I have an idea what you want. – Quimby May 13 '22 at 09:42
  • @Quimby https://stackoverflow.com/questions/72227859/how-to-call-a-function-at-periodic-interval-that-takes-in-an-object-as-argument this is what I want – suravshrestha May 13 '22 at 10:09
  • What happens when a `detach`ed thread does not finish its execution before the exit of the main thread? Is it safe if a thread is left running when the main function exits? I tried it with a very simple example and nothing went wrong. I might be wrong though. – digito_evo May 13 '22 at 18:57
  • 1
    @digito_evo Usually, when main returns, the process is destroyed and with it all its threads. But it is not guaranteed by C++, that is implementation-defined and depends on the OS. In theory, the process could hang until all threads exit, but the sane option is to terminate them. In practice, I would not worry about that at all, but be careful that the thread will be destroyed at any moment, so if it modifies some files or a database, it might be leave them in undetermined state. – Quimby May 13 '22 at 20:06
  • 1
    Yes got it, tnx. I'll be careful. However this whole C++ concurrency stuff seems too complicated for me. Where do you think I should start to learn it? – digito_evo May 13 '22 at 21:10
  • 1
    @digito_evo [curated book list](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). You might be interested in *C++ concurrency in action*, I've read only the first edition but it is very good. Also I would recommend going through cppreference on threading and look at the examples. In general that site has very precise documentation on all of C++. *Effective modern C++* is very nice book too. – Quimby May 14 '22 at 05:49
  • Nice. Fortunately I have the digital versions of both books. I should get into it soon. – digito_evo May 14 '22 at 07:26