Created
March 14, 2019 18:45
-
-
Save RedBeard0531/b8b0a7b41e7bdaddbbddb9d226df2452 to your computer and use it in GitHub Desktop.
Example of non-sequential consistency
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// {{{ | |
// vim: set foldmethod=marker: | |
// g++ -O3 -pthread sc.cpp && ./a.out | |
#include <cstdio> | |
#include <thread> | |
#include <atomic> | |
using namespace std; | |
constexpr auto load_order = memory_order_acquire; | |
constexpr auto store_order = memory_order_release; | |
constexpr bool run_until_boom = false; | |
// {{{ | |
constexpr int alignment = false ? 4 : 1024*1024; | |
constexpr long long loops = 10; | |
constexpr int nThreads = 3; // Includes checker | |
alignas(alignment) atomic<int> a {0}; | |
alignas(alignment) atomic<int> b {0}; | |
alignas(alignment) atomic<int> barrier1 {0}; | |
alignas(alignment) atomic<int> barrier2 {0}; | |
alignas(alignment) atomic<int> barrier3 {0}; | |
alignas(alignment) atomic<int> r1 {0}; | |
alignas(alignment) atomic<int> r2 {0}; | |
int load(atomic<int>& i) { | |
asm volatile("":::"memory"); | |
return i.load(load_order); | |
asm volatile("":::"memory"); | |
} | |
void store(atomic<int>& i, int val) { | |
asm volatile("":::"memory"); | |
i.store(val, store_order); | |
asm volatile("":::"memory"); | |
} | |
inline void arrive_and_wait(atomic<int>& barrier) { | |
barrier += 1; | |
while (barrier.load() < nThreads) { | |
} | |
} | |
template <typename F> | |
void run(F&& f) { | |
thread([f = std::forward<F>(f)] { | |
while(true){ | |
arrive_and_wait(barrier1); | |
f(); | |
arrive_and_wait(barrier2); | |
arrive_and_wait(barrier3); | |
} | |
}).detach(); | |
} | |
template <typename F> | |
auto checker(F&& f) { | |
arrive_and_wait(barrier1); | |
for (long long i = 0; i < loops || run_until_boom; i++) { | |
arrive_and_wait(barrier2); | |
barrier1 = 0; | |
const bool test = f(); | |
if (!run_until_boom) { | |
printf("r1=%d r2=%d %s\n", r1.load(), r2.load(), test ? "!!!" : ""); | |
} else if (test) { | |
printf("boom after %lld successes\n", i); | |
return; | |
} else if (i && i % 1'000'000 == 0) { | |
printf("%lldM successes\n", i/1'000'000); | |
} | |
// Reset state | |
a = 0; | |
b = 0; | |
arrive_and_wait(barrier3); | |
barrier2 = 0; | |
arrive_and_wait(barrier1); | |
barrier3 = 0; | |
} | |
} | |
// }}} | |
// }}} | |
int main() { | |
run([] { | |
store(a, 1); | |
r1 = load(b); | |
}); | |
run([] { | |
store(b, 1); | |
r2 = load(a); | |
}); | |
checker([] { | |
return r1 == 0 && r2 == 0; | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment