2016-02-23 23:16:51 +00:00
|
|
|
#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 {
|
|
|
|
|
2019-09-22 21:19:10 +00:00
|
|
|
template<typename T> struct left_right {
|
|
|
|
template<typename Func> void update(Func &&f)
|
2016-02-23 23:16:51 +00:00
|
|
|
{
|
|
|
|
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 = 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;
|
2019-09-22 21:19:10 +00:00
|
|
|
std::atomic_long readers[2];
|
|
|
|
std::mutex write_mutex;
|
2016-02-23 23:16:51 +00:00
|
|
|
|
|
|
|
T data[2] = {{}, {}};
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|