Stopping a thread that runs an action periodically
Your code is almost correct. Here's your code stripped down:

    while (true)
    {
        auto next_flush = prev_flush + flush_interval_;
        std::unique_lock&lt;std::mutex&gt; lock{flush_stop_mutex_};
        auto stop_reason = flush_stop_cv_.wait_until(lock, next_flush);

        // stopping logic omitted
    }


Notice that the unique_lock is destroyed at the }, and so the mutex is not locked for a little while, until the next time you loop around and hit the std::unique_lock line. If another thread destroys the Logger during this period, it'll notify flush_stop_cv_ but you won't be listening and so you'll miss the notification... and that was your one chance to hear it, so now you'll never stop and your program is frozen.

Solution: If you're waiting for a notification that you absolutely must hear, then absolutely do not stop listening. Don't drop that lock!

    std::unique_lock&lt;std::mutex&gt; lock{flush_stop_mutex_};
    while (true)
    {
        auto next_flush = prev_flush + flush_interval_;
        auto stop_reason = flush_stop_cv_.wait_until(lock, next_flush);

        // stopping logic omitted
    }


Or if you're really worried about holding the mutex for some reason, then check again after taking the lock but before going to sleep:

    while (true)
    {
        auto next_flush = prev_flush + flush_interval_;
        std::unique_lock&lt;std::mutex&gt; lock{flush_stop_mutex_};
        if (flush_stop_) break;  // IMPORTANT LINE ADDED
        auto stop_reason = flush_stop_cv_.wait_until(lock, next_flush);

        // stopping logic omitted
    }


Otherwise, looks good to me.



condition_variable::wait_until is a fairly obscure function, IMO. Here you're assuming that it is implemented correctly and efficiently. I'm not sure that it always is, but I have no evidence to the contrary. The only immediately obvious way to get rid of wait_until is almost certainly worse: You could set another thread to notify the condition variable every flush_interval_ seconds, and detect spurious wakeups by computing std::chrono::system_clock::now() - prev_flush_, instead of by looking for std::cv_status::timeout.