#include <atomic>
#include <iostream>
template <class T> class Seqlock {
std::atomic<int> seq_;
T val_;
public:
Seqlock(T value = T())
: val_(value) {
}
// concurrent calls are NOT allowed
void store(T value) {
const int seq0 = seq_.load(std::memory_order_relaxed);
seq_.store(seq0 + 1, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
val_ = value;
std::atomic_thread_fence(std::memory_order_release);
seq_.store(seq0 + 2, std::memory_order_relaxed);
}
// concurrent calls are allowed
T load() const {
for (;;) {
const int seq0 = seq_.load(std::memory_order_relaxed);
if (seq0 & 1) {
// cpu_relax()
continue;
}
std::atomic_thread_fence(std::memory_order_acquire);
T ret = val_;
std::atomic_thread_fence(std::memory_order_acquire);
const int seq1 = seq_.load(std::memory_order_relaxed);
if (seq0 == seq1) {
return ret;
}
}
}
};
int main() {
Seqlock<int> sl;
sl.store(123);
std::cout << sl.load() << "\n";
return 0;
}
I2luY2x1ZGUgPGF0b21pYz4KI2luY2x1ZGUgPGlvc3RyZWFtPgoKdGVtcGxhdGUgPGNsYXNzIFQ+IGNsYXNzIFNlcWxvY2sgewogICAgc3RkOjphdG9taWM8aW50PiBzZXFfOwogICAgVCB2YWxfOwoKcHVibGljOgogICAgU2VxbG9jayhUIHZhbHVlID0gVCgpKQogICAgICAgIDogdmFsXyh2YWx1ZSkgewogICAgfQoKICAgIC8vIGNvbmN1cnJlbnQgY2FsbHMgYXJlIE5PVCBhbGxvd2VkCiAgICB2b2lkIHN0b3JlKFQgdmFsdWUpIHsKICAgICAgICBjb25zdCBpbnQgc2VxMCA9IHNlcV8ubG9hZChzdGQ6Om1lbW9yeV9vcmRlcl9yZWxheGVkKTsKICAgICAgICBzZXFfLnN0b3JlKHNlcTAgKyAxLCBzdGQ6Om1lbW9yeV9vcmRlcl9yZWxheGVkKTsKCiAgICAgICAgc3RkOjphdG9taWNfdGhyZWFkX2ZlbmNlKHN0ZDo6bWVtb3J5X29yZGVyX3JlbGVhc2UpOwoKICAgICAgICB2YWxfID0gdmFsdWU7CiAgICAgICAgc3RkOjphdG9taWNfdGhyZWFkX2ZlbmNlKHN0ZDo6bWVtb3J5X29yZGVyX3JlbGVhc2UpOwoKICAgICAgICBzZXFfLnN0b3JlKHNlcTAgKyAyLCBzdGQ6Om1lbW9yeV9vcmRlcl9yZWxheGVkKTsKICAgIH0KCiAgICAvLyBjb25jdXJyZW50IGNhbGxzIGFyZSBhbGxvd2VkCiAgICBUIGxvYWQoKSBjb25zdCB7CiAgICAgICAgZm9yICg7OykgewogICAgICAgICAgICBjb25zdCBpbnQgc2VxMCA9IHNlcV8ubG9hZChzdGQ6Om1lbW9yeV9vcmRlcl9yZWxheGVkKTsKICAgICAgICAgICAgaWYgKHNlcTAgJiAxKSB7CiAgICAgICAgICAgICAgICAvLyBjcHVfcmVsYXgoKQogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHN0ZDo6YXRvbWljX3RocmVhZF9mZW5jZShzdGQ6Om1lbW9yeV9vcmRlcl9hY3F1aXJlKTsKCiAgICAgICAgICAgIFQgcmV0ID0gdmFsXzsKICAgICAgICAgICAgc3RkOjphdG9taWNfdGhyZWFkX2ZlbmNlKHN0ZDo6bWVtb3J5X29yZGVyX2FjcXVpcmUpOwoKICAgICAgICAgICAgY29uc3QgaW50IHNlcTEgPSBzZXFfLmxvYWQoc3RkOjptZW1vcnlfb3JkZXJfcmVsYXhlZCk7CiAgICAgICAgICAgIGlmIChzZXEwID09IHNlcTEpIHsKICAgICAgICAgICAgICAgIHJldHVybiByZXQ7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn07CgppbnQgbWFpbigpIHsKICAgIFNlcWxvY2s8aW50PiBzbDsKICAgIHNsLnN0b3JlKDEyMyk7CiAgICBzdGQ6OmNvdXQgPDwgc2wubG9hZCgpIDw8ICJcbiI7CiAgICByZXR1cm4gMDsKfQ==