0

I want to design a timer in c++, to execute my function after a fixed time.

the code likes like:

#include <thread>
typedef void (*callback)();
class timer {
 public:
   void start(int sec, callback f) {
     std::thread t([&sec, &f]() {sleep(sec); f();});
   }
};

void test () {
  printf("here called\n");
}
int main() {
  timer t;
  t.start(3, test);
  while (1);
}

but when i run this code, i got:

terminate called without an active exception
[1]    3168208 abort (core dumped)  ./a.out

can you help on this? and, any suggestions for a more flexible timer design?

nick
  • 832
  • 3
  • 12
  • `sleep` is purely platform-specific. I think you are looking for: `std::this_thread::sleep_for(std::chrono::seconds(sec));` (Include ``) – Ruks Aug 05 '21 at 02:04
  • 1
    Additionally, you have a problem where `t` captures `sec` and `callback` by reference, but those are references to variables local to `start` whose lifetime ends as soon as `start` returns. – Nathan Pierson Aug 05 '21 at 02:05

2 Answers2

3

You created a std::thread and destructed it without detaching it.

std::thread t([&sec, &f]() {sleep(sec);

Either call join to wait on it, or call detach.

Note also the capture by reference issue in your comments.

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • and could you teach me how to make it work when the function is a class member function(not static)? – nick Aug 05 '21 at 02:08
  • You must also pass `this` to the thread as a parameter. https://stackoverflow.com/questions/10673585/start-thread-with-member-function – Michael Chourdakis Aug 05 '21 at 02:09
2

There are a few problems with your code that need to be addressed:

  1. After spawning a std::thread you need to synchronize it using std::thread::join().
  2. Remove the reference capture from the sec parameter in order to prevent dangling of references by the end of the scope of start().
  3. sleep() is platform-dependent, so your code will only work for certain platforms that support it. Instead use, std::this_thread::sleep_for(std::chrono::seconds(sec));
#include <thread>
#include <chrono> // For std::chrono
#include <cstdio> // For printf

typedef void (*callback)();

class timer {
    // Bring the thread object outside the function and make it an instance variable of the class
    std::thread t;
public:
    // Spawns a thread
    void start(int const sec, callback&& f) {
        if (t.joinable()) // If the object already has a thread attached to it, call 'join()' on it
            t.join();
        /* Capture 'sec' by value as it is a local variable, consequently, capture
          'f' by reference as it is a function and its lifetime is throughout the whole
          program */
        t = std::thread([sec, &f]() {
                std::this_thread::sleep_for(std::chrono::seconds(sec));
                f();
            });
    }
    // After the class gets destroyed, the thread is synchronized
    ~timer() {
        t.join();
    }
};

void test () {
    printf("here called\n");
}

int main() {
    timer t;
    t.start(3, test);
}
Ruks
  • 3,886
  • 1
  • 10
  • 22