A new question about a revised version of the code in this question, based on the advice in the accepted answer can be found here.
I need to signal my program to do something every X seconds. So I decided to make a separate thread that sends such a signal using ZeroMQ. All other behaviour is also triggered by ZeroMQ messages, so this seems like a safe way to do it, with respect to multithreading.
I have never used threads in C++ before though, so I'd like some feedback on my code. Note that in the code below I have replaced the actual task with a simple cout
statement.
EDIT: I just realized the thread could very well terminate between setting run = false
and calling join
, which causes a std::system_error
to be thrown. Putting the join statement in an if
-block with isjoinable
still suffers from the same problem. How should I handle this? try-catch? Using a locking mechanism instead of an atomic bool?
Ticker.hpp
#include <thread>
#include <chrono>
#include <atomic>
class Ticker {
private:
const unsigned int interval;
std::atomic_bool run;
std::thread tickthread;
public:
Ticker(unsigned int interval);
Ticker(const Ticker& orig) = delete;
virtual ~Ticker();
void stop();
private:
void tickfunction();
};
Ticker.cpp
#include "Ticker.hpp"
#include <iostream>
using namespace std;
Ticker::Ticker(unsigned int interval)
: interval(interval), run(true), tickthread(&Ticker::tickfunction, this) {
}
Ticker::~Ticker() {
if (tickthread.joinable()) {
stop();
}
}
void Ticker::stop() {
cout << "stopping..." << endl;
run = false;
// interrupt sleep?
tickthread.join();
cout << "joined" << endl;
}
void Ticker::tickfunction() {
while (true) {
this_thread::sleep_for(chrono::seconds(interval));
if (run) {
cout << "tick" << endl;
} else {
break;
}
}
}
There are also two specific things I'd like recommendations on:
How can I change this class to accept any std::chrono::duration object as input for the interval, instead of just an integer? I tried this, but couldn't figure out how to do it with the templates.
Is there a way to interrupt the sleep_for when I call
stop()
? Especially wheninterval
is large, it'd be nice to not have to wait for the sleeping thread when stopping it.