Initialize atomics in metrics, update style guide on atomics
This commit is contained in:
@@ -176,6 +176,7 @@ struct Metric {
|
|||||||
family->p->perThreadState[std::this_thread::get_id()].instances[key];
|
family->p->perThreadState[std::this_thread::get_id()].instances[key];
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
ptr = std::make_unique<Counter::State>();
|
ptr = std::make_unique<Counter::State>();
|
||||||
|
ptr->value.store(0, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
Counter result;
|
Counter result;
|
||||||
result.p = ptr.get();
|
result.p = ptr.get();
|
||||||
@@ -190,6 +191,7 @@ struct Metric {
|
|||||||
auto &ptr = family->p->instances[key];
|
auto &ptr = family->p->instances[key];
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
ptr = std::make_unique<Gauge::State>();
|
ptr = std::make_unique<Gauge::State>();
|
||||||
|
ptr->value = 0.0;
|
||||||
}
|
}
|
||||||
Gauge result;
|
Gauge result;
|
||||||
result.p = ptr.get();
|
result.p = ptr.get();
|
||||||
@@ -210,8 +212,12 @@ struct Metric {
|
|||||||
ptr->thresholds = family->p->buckets; // Already sorted and deduplicated
|
ptr->thresholds = family->p->buckets; // Already sorted and deduplicated
|
||||||
|
|
||||||
// DESIGN: std::atomic is not copy-constructible
|
// DESIGN: std::atomic is not copy-constructible
|
||||||
// Initialize vector with correct size, all atomics default to 0
|
// Initialize vector with correct size, all atomics explicitly initialized
|
||||||
|
// to 0
|
||||||
ptr->counts = std::vector<AtomicWord>(ptr->thresholds.size());
|
ptr->counts = std::vector<AtomicWord>(ptr->thresholds.size());
|
||||||
|
for (auto &count : ptr->counts) {
|
||||||
|
count.store(0, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
ptr->sum.store(0, std::memory_order_relaxed);
|
ptr->sum.store(0, std::memory_order_relaxed);
|
||||||
ptr->observations.store(0, std::memory_order_relaxed);
|
ptr->observations.store(0, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
@@ -232,8 +238,8 @@ void Counter::inc(double x) {
|
|||||||
std::memory_order_relaxed);
|
std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
void Gauge::inc(double x) {
|
void Gauge::inc(double x) {
|
||||||
// IMPLEMENTATION DETAIL: Gauges currently support multiple writers via mutex,
|
// IMPLEMENTATION DETAIL: Mutex protection used internally for thread safety,
|
||||||
// though the public API documents single-writer semantics for consistency
|
// but API contract remains single-writer per instance
|
||||||
std::unique_lock<std::mutex> _{p->mutex};
|
std::unique_lock<std::mutex> _{p->mutex};
|
||||||
p->value += x;
|
p->value += x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ private:
|
|||||||
// THREAD SAFETY: Each gauge instance has exactly ONE writer thread (the one
|
// THREAD SAFETY: Each gauge instance has exactly ONE writer thread (the one
|
||||||
// that created it). It is an error to call inc()/dec()/set() from any thread
|
// that created it). It is an error to call inc()/dec()/set() from any thread
|
||||||
// other than the creating thread.
|
// other than the creating thread.
|
||||||
|
// IMPLEMENTATION NOTE: Mutex protection is an internal implementation detail.
|
||||||
struct Gauge {
|
struct Gauge {
|
||||||
void inc(double = 1.0); // Increase gauge value - SINGLE WRITER ONLY
|
void inc(double = 1.0); // Increase gauge value - SINGLE WRITER ONLY
|
||||||
void dec(double = 1.0); // Decrease gauge value - SINGLE WRITER ONLY
|
void dec(double = 1.0); // Decrease gauge value - SINGLE WRITER ONLY
|
||||||
|
|||||||
21
style.md
21
style.md
@@ -301,6 +301,27 @@ for (auto &precondition : preconditions_) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Atomic Operations
|
||||||
|
- **Never use assignment operators** with `std::atomic` - always use explicit `store()` and `load()`
|
||||||
|
- **Always specify memory ordering** explicitly for atomic operations
|
||||||
|
- **Use the least restrictive correct memory ordering** - choose the weakest ordering that maintains correctness
|
||||||
|
```cpp
|
||||||
|
// Preferred - explicit store/load with precise memory ordering
|
||||||
|
std::atomic<uint64_t> counter;
|
||||||
|
counter.store(42, std::memory_order_relaxed); // Single-writer metric updates
|
||||||
|
auto value = counter.load(std::memory_order_relaxed); // Reading metrics for display
|
||||||
|
|
||||||
|
counter.store(1, std::memory_order_release); // Publishing initialization
|
||||||
|
auto ready = counter.load(std::memory_order_acquire); // Synchronizing with publisher
|
||||||
|
|
||||||
|
counter.store(42, std::memory_order_seq_cst); // When sequential consistency needed
|
||||||
|
|
||||||
|
// Avoid - assignment operators (implicit memory ordering)
|
||||||
|
std::atomic<uint64_t> counter;
|
||||||
|
counter = 42; // Implicit - memory ordering not explicit
|
||||||
|
auto value = counter; // Implicit - memory ordering not explicit
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Memory Management
|
## Memory Management
|
||||||
|
|||||||
Reference in New Issue
Block a user