Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
atomic: Atomic operations in concurrent systems

Arene Base provides facilities for atomic operations across threads that do not depend on the C++ standard library.

The public header is

Public export header for the atomic subpackage.

The Bazel target is

//:atomic

Introduction

The atomic subpackage provides atomic operations and types. It is intended as an alternative to the C++ standard libarary <atomic> header, for environments where the standard library implementation is not available.

Types

atomic_counter

The atomic_counter class provides a thread-safe counter implementation using compiler intrinsics rather than standard library facilities.

arene::base::atomic_counter counter;

API Reference

Constructors
constexpr atomic_counter() noexcept;
constexpr explicit atomic_counter(uint64_t initial_value) noexcept;
Operations
// Pre-increment
auto operator++() noexcept -> uint64_t;
// Post-increment
auto operator++(int) noexcept -> uint64_t;
// Pre-decrement
auto operator--() noexcept -> uint64_t;
// Post-decrement
auto operator--(int) noexcept -> uint64_t;
// Addition assignment
auto operator+=(uint64_t val) noexcept -> uint64_t;
// Subtraction assignment
auto operator-=(uint64_t val) noexcept -> uint64_t;
Value Access
// Explicit load
auto load() const noexcept -> uint64_t;
// Implicit conversion
operator uint64_t() const noexcept;

Thread Safety

All operations on atomic_counter are atomic and thread-safe. The implementation uses compiler intrinsics with sequential consistency memory ordering to ensure proper behavior in multi-threaded environments.

Examples

Basic Usage
// Simple increment example
auto basic_usage() -> void {
atomic_monotonic_counter counter;
// Pre-increment - prints "New value: 1"
uint64_t new_value = ++counter;
std::cout << "New value: " << new_value << std::endl;
// Post-increment - prints "Previous value: 1"
uint64_t prev_value = counter++;
std::cout << "Previous value: " << prev_value << std::endl;
// Read the value using implicit conversion - prints "Value: 7"
uint64_t value = counter;
std::cout << "Value: " << value << std::endl;
// Read the value using explicit load - prints "Same value: 7"
uint64_t same_value = counter.load();
std::cout << "Same value: " << same_value << std::endl;
}
Thread-Safe Counting
// Example with concurrent updates
auto concurrent_updates() -> void {
atomic_monotonic_counter shared_counter;
constexpr int num_threads = 4;
constexpr int iterations = 1000;
// Create multiple threads that increment the counter
std::vector<std::thread> threads;
for (int i = 0; i < num_threads; ++i) {
threads.emplace_back([&shared_counter]() {
for (int j = 0; j < iterations; ++j) {
++shared_counter;
}
});
}
// Wait for all threads to complete
for (auto& t : threads) {
t.join();
}
// The final value should be num_threads * iterations
uint64_t final_value = shared_counter;
printf("Final counter value: %lu (expected: %d)\n", final_value, num_threads * iterations);
}
Using Counter for Event Tracking
// Using atomic_monotonic_counter to track events
auto counter_as_event_tracker() -> void {
atomic_monotonic_counter requests(0);
atomic_monotonic_counter completed(0);
atomic_monotonic_counter errors(0);
// Simulate processing requests
auto process_request = [&](int id) -> void {
++requests;
// Simulate work
bool success = (id % 10 != 0); // 10% error rate
if (success) {
++completed;
} else {
++errors;
}
};
// Process some requests
for (int i = 0; i < 100; ++i) {
process_request(i);
}
// Report statistics
printf("Requests: %lu\n", requests.load());
printf("Completed: %lu\n", completed.load());
printf("Errors: %lu\n", errors.load());
}