123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- #pragma once
- #include <atomic>
- #include <mutex>
- #include <thread>
- #include <cinttypes>
- // left_right based on
- // https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/left-right-2014.pdf
- // see concurrencyfreaks.com
- namespace left_right {
- template<typename T> struct left_right {
- template<typename Func> void update(Func &&f)
- {
- std::lock_guard<std::mutex> lock(write_mutex);
- auto cur = current.load();
- auto next = (cur + 1) & 1;
- while (readers[next] != 0)
- std::this_thread::yield();
- f(data[next]);
- current = (std::uint_fast8_t)next;
- while (readers[cur] != 0)
- std::this_thread::yield();
- f(data[cur]);
- }
- T read()
- {
- auto cur = current.load();
- for (;;) {
- readers[cur] += 1;
- auto cur_ = current.load();
- if (cur_ == cur)
- break;
- readers[cur] -= 1;
- cur = cur_;
- }
- auto val = data[cur];
- readers[cur] -= 1;
- return val;
- }
- private:
- std::atomic_uint_fast8_t current;
- std::atomic_long readers[2];
- std::mutex write_mutex;
- T data[2] = {{}, {}};
- };
- } // namespace left_right
|