I have a thread class similar to this:
class thr {
void run() {
for (;;) {
// block on a queue
// do some processing
++loops_;
}
}
void get_metrics(int& qps) {
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
double delta = std::chrono::duration<double>(now - last_metrics_time_).count();
qps = std::round(loops_ / delta);
loops_ = 0;
last_metrics_time_ = now;
}
static std::atomic<int> loops_;
static std::chrono::steady_clock::time_point last_metrics_time_;
};
std::atomic<int> thr::loops_ { 0 };
std::chrono::steady_clock::time_point thr::last_metrics_time_ {
std::chrono::steady_clock::now() // initial value: when the program starts
};
There are many instances of this running. There is another thread which calls get_metrics() from time to time.
I would like to prevent run()
from being able to access last_metrics_time_
, because it's not atomic (there's only one metrics collector thread, so no problem there).
Making last_metrics_time_
a static variable local to get_metrics
doesn't seem right, because it will get initialized when get_metrics
is first called, rather than when the program starts. This would result in a near-zero value for delta
(because now
will be very close to last_metrics_time_
) and a huge value returned for the first call.
No.
But you could split this multiple-responsibility class into two single-responsibility classes: one running the loop, updating loops_
, and providing read-only access to it, the other calculating the metrics and recording the time. Then each function will only have access to what it needs.