MiddleCodeOccasionalNot answered yet
Write a basic std::atomic<T> implementation.
Implement a minimal Atomic<T> wrapper providing load, store, exchange and compare_exchange_strong.
Requirements:
- guard the value so every operation is atomic;
compare_exchange_strongmust compare-and-swap as one indivisible step (aloadthen a separate conditionalstoreis not atomic) - on a failed
compare_exchange_strong, write the current value back intoexpected - make the wrapper non-copyable
- this mutex-based version is the didactic baseline — a real
std::atomic<T>uses lock-free CPU instructions for trivially-copyable types, not a mutex
template<typename T>
class Atomic {
public:
Atomic();
explicit Atomic(T val);
T load() const;
void store(T desired);
T exchange(T desired);
bool compare_exchange_strong(T& expected, T desired);
// your code here
};
Write the implementation.
A minimal Atomic<T> wraps a value and mutex with load/store/compare_exchange_strong. A real std::atomic<T> for trivially-copyable types uses lock-free CPU instructions via intrinsics — no mutex needed.
- ✗Forgetting to protect
compare_exchange_strongatomically — a load + conditional store with a gap between them is not atomic and defeats the purpose - ✗Using
volatileinstead of atomics for inter-thread communication —volatileprevents reordering by the compiler but not by the CPU - ✗Omitting memory_order parameters — the default
memory_order_seq_cstis correct but the most expensive; for simple flagsmemory_order_acquire/releaseis sufficient
- →How does the CPU guarantee atomicity of a 64-bit read on x86-64 without a LOCK prefix?
- →What is ABA problem and how does
std::atomic<std::shared_ptr<T>>help?
Contents
Basic std::atomic Implementation
Version 1: mutex-based (portable, didactic)
#include <mutex>
#include <utility>
template<typename T>
class Atomic {
public:
Atomic() = default;
explicit Atomic(T val) : val_(std::move(val)) {}
Atomic(const Atomic&) = delete;
Atomic& operator=(const Atomic&) = delete;
T load() const {
std::lock_guard lock(mu_);
return val_;
}
void store(T desired) {
std::lock_guard lock(mu_);
val_ = std::move(desired);
}
// Returns true on success; on failure writes current value into expected
bool compare_exchange_strong(T& expected, T desired) {
std::lock_guard lock(mu_);
if (val_ == expected) {
val_ = std::move(desired);
return true;
}
expected = val_;
return false;
}
T exchange(T desired) {
std::lock_guard lock(mu_);
T old = std::move(val_);
val_ = std::move(desired);
return old;
}
operator T() const { return load(); }
private:
mutable std::mutex mu_;
T val_{};
};
Version 2: lock-free for trivially_copyable T (gcc/clang)
#include <type_traits>
template<typename T>
class LockFreeAtomic {
static_assert(std::is_trivially_copyable_v<T>);
static_assert(sizeof(T) <= 8); // guaranteed lock-free on x86-64
public:
explicit LockFreeAtomic(T val = {}) : val_(val) {}
T load(int order = __ATOMIC_SEQ_CST) const {
T result;
__atomic_load(&val_, &result, order);
return result;
}
void store(T desired, int order = __ATOMIC_SEQ_CST) {
__atomic_store(&val_, &desired, order);
}
bool compare_exchange_strong(T& expected, T desired,
int success = __ATOMIC_SEQ_CST,
int failure = __ATOMIC_SEQ_CST) {
return __atomic_compare_exchange(&val_, &expected, &desired,
false, success, failure);
}
private:
T val_;
};
Test
#include <cassert>
#include <thread>
#include <vector>
int main() {
// Test 1: basic operations
Atomic<int> a(0);
a.store(42);
assert(a.load() == 42);
int expected = 42;
assert(a.compare_exchange_strong(expected, 100));
assert(a.load() == 100);
expected = 0; // wrong expected
assert(!a.compare_exchange_strong(expected, 999));
assert(expected == 100); // updated with current value
// Test 2: concurrent increment
Atomic<int> counter(0);
const int N = 1000;
std::vector<std::thread> threads;
for (int i = 0; i < N; ++i) {
threads.emplace_back([&counter] {
int old = counter.load();
while (!counter.compare_exchange_strong(old, old + 1))
; // CAS loop
});
}
for (auto& t : threads) t.join();
assert(counter.load() == N);
}
Comparison
| Trait | Mutex | __atomic_* builtin | std::atomic<T> |
|---|---|---|---|
| Portability | Any platform | GCC/Clang | Standard C++11 |
| Lock-free | No | Yes (if is_lock_free()) | Yes (small types) |
| Shared memory | No | Yes | Implementation-defined |
| Overhead | High | Minimal | Minimal |
Contents