1616
1717#include < thread> // NOLINT
1818
19+ #include " absl/memory/memory.h"
1920#include " absl/synchronization/mutex.h"
2021#include " absl/time/clock.h"
2122#include " absl/time/time.h"
@@ -41,9 +42,15 @@ class StatsExporterImpl {
4142 views_.erase (std::string (name));
4243 }
4344
45+ // Adds a handler, which cannot be subsequently removed (except by
46+ // ClearHandlersForTesting()). The background thread is started when the
47+ // first handler is registered.
4448 void RegisterHandler (std::unique_ptr<StatsExporter::Handler> handler) {
4549 absl::MutexLock l (&mu_);
4650 handlers_.push_back (std::move (handler));
51+ if (!thread_started_) {
52+ StartExportThread ();
53+ }
4754 }
4855
4956 void Export () {
@@ -59,7 +66,7 @@ class StatsExporterImpl {
5966 }
6067
6168 private:
62- StatsExporterImpl () : t_(&StatsExporterImpl::RunWorkerLoop, this ) {}
69+ StatsExporterImpl () {}
6370
6471 void SendToHandlers (const ViewDescriptor& descriptor, const ViewData& data)
6572 SHARED_LOCKS_REQUIRED(mu_) {
@@ -68,10 +75,20 @@ class StatsExporterImpl {
6875 }
6976 }
7077
78+ void StartExportThread () EXCLUSIVE_LOCKS_REQUIRED(mu_) {
79+ t_ = std::thread (&StatsExporterImpl::RunWorkerLoop, this );
80+ thread_started_ = true ;
81+ }
82+
7183 // Loops forever, calling Export() every export_interval_.
7284 void RunWorkerLoop () {
85+ absl::Time next_export_time = absl::Now () + export_interval_;
7386 while (true ) {
74- absl::SleepFor (export_interval_);
87+ // SleepFor() returns immediately when given a negative duration.
88+ absl::SleepFor (next_export_time - absl::Now ());
89+ // In case the last export took longer than the export interval, we
90+ // calculate the next time from now.
91+ next_export_time = absl::Now () + export_interval_;
7592 Export ();
7693 }
7794 }
@@ -83,7 +100,9 @@ class StatsExporterImpl {
83100 std::vector<std::unique_ptr<StatsExporter::Handler>> handlers_
84101 GUARDED_BY (mu_);
85102 std::unordered_map<std::string, std::unique_ptr<View>> views_ GUARDED_BY (mu_);
86- std::thread t_;
103+
104+ bool thread_started_ GUARDED_BY (mu_) = false;
105+ std::thread t_ GUARDED_BY (mu_);
87106};
88107
89108void StatsExporter::AddView (const ViewDescriptor& view) {
0 commit comments