-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory-order-cpp11.cpp
More file actions
63 lines (47 loc) · 2.18 KB
/
memory-order-cpp11.cpp
File metadata and controls
63 lines (47 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <atomic>
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunused-value"
#define CATCH_CONFIG_MAIN // Tells Catch2 to provide a main()
#include "../catch/catch_amalgamated.hpp"
#include "utils.h"
using namespace std;
//// memory order
// 6 memory orders — from strictest to most relaxed
// std::memory_order_seq_cst — default, strongest, slowest
// std::memory_order_acquire — pairs with release (load side)
// std::memory_order_release — pairs with acquire (store side)
// std::memory_order_acq_rel — both acquire and release (read-modify-write)
// std::memory_order_consume — weak acquire (rarely used, avoid)
// std::memory_order_relaxed — no ordering, fastest
//
//// key notes
// - default (seq_cst) is always correct — relax only for perf
// - acquire/release: most common optimization — producer/consumer pattern
// - relaxed: only safe when operations are truly independent
// - consume: avoid — compilers treat it as acquire anyway
// - wrong memory order = data race = UB — subtle, hard to debug
// - on x86: seq_cst is cheap (strong memory model); on ARM: expensive
TEST_CASE("mem-ord-1") {
//// problem - using relaxed order
std::atomic<bool> ready = false;
std::atomic<int> data = 0;
// Thread 1
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_relaxed);
// Thread 2
if (ready.load(std::memory_order_relaxed))
// data might still be 0 here! CPU can reorder,
// Thread 2 may see ready=true but data=0
std::cout << data.load(std::memory_order_relaxed);
//// solved
std::atomic<bool> ready_ = false;
std::atomic<int> data_ = 0;
// Thread 1
data_.store(42, std::memory_order_relaxed); // data doesn't need sync
ready_.store(true, std::memory_order_release); // "publish" — everything
// above is visible
// Thread 2
if (ready_.load(std::memory_order_acquire)) // "subscribe" — sees
// everything before release
cout << data.load(memory_order_relaxed); // guaranteed to be 42
}