left-right.hpp 1006 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #pragma once
  2. #include <atomic>
  3. #include <mutex>
  4. #include <thread>
  5. #include <cinttypes>
  6. // left_right based on
  7. // https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/left-right-2014.pdf
  8. // see concurrencyfreaks.com
  9. namespace left_right {
  10. template<typename T> struct left_right {
  11. template<typename Func> void update(Func &&f)
  12. {
  13. std::lock_guard<std::mutex> lock(write_mutex);
  14. auto cur = current.load();
  15. auto next = (cur + 1) & 1;
  16. while (readers[next] != 0)
  17. std::this_thread::yield();
  18. f(data[next]);
  19. current = next;
  20. while (readers[cur] != 0)
  21. std::this_thread::yield();
  22. f(data[cur]);
  23. }
  24. T read()
  25. {
  26. auto cur = current.load();
  27. for (;;) {
  28. readers[cur] += 1;
  29. auto cur_ = current.load();
  30. if (cur_ == cur)
  31. break;
  32. readers[cur] -= 1;
  33. cur = cur_;
  34. }
  35. auto val = data[cur];
  36. readers[cur] -= 1;
  37. return val;
  38. }
  39. private:
  40. std::atomic_uint_fast8_t current;
  41. std::atomic_long readers[2];
  42. std::mutex write_mutex;
  43. T data[2] = {{}, {}};
  44. };
  45. }