left-right.hpp 1.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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>
  11. struct left_right {
  12. template <typename Func>
  13. void update(Func &&f)
  14. {
  15. std::lock_guard<std::mutex> lock(write_mutex);
  16. auto cur = current.load();
  17. auto next = (cur + 1) & 1;
  18. while (readers[next] != 0)
  19. std::this_thread::yield();
  20. f(data[next]);
  21. current = next;
  22. while (readers[cur] != 0)
  23. std::this_thread::yield();
  24. f(data[cur]);
  25. }
  26. T read()
  27. {
  28. auto cur = current.load();
  29. for (;;) {
  30. readers[cur] += 1;
  31. auto cur_ = current.load();
  32. if (cur_ == cur)
  33. break;
  34. readers[cur] -= 1;
  35. cur = cur_;
  36. }
  37. auto val = data[cur];
  38. readers[cur] -= 1;
  39. return val;
  40. }
  41. private:
  42. std::atomic_uint_fast8_t current;
  43. std::atomic_long readers[2];
  44. std::mutex write_mutex;
  45. T data[2] = {{}, {}};
  46. };
  47. }