First implementation of Conncurent lockfree list.

This commit is contained in:
Kruno Tomola Fabro 2016-08-02 22:00:30 +01:00
parent f226a9d6c5
commit e4238d5871
2 changed files with 232 additions and 5 deletions
src/data_structures

View File

@ -352,11 +352,13 @@ public:
return succs[0]->value();
}
bool has_next()
{
assert(succs[0] != nullptr);
return succs[0].forward(0) != nullptr;
}
// WRONG THIS CAN POSSIBLY NOT BE TRUE IF SOMEONE JUST AFTER THIS REMOVE
// ELEMENT AFTER THIS ONE.
// bool has_next()
// {
// assert(succs[0] != nullptr);
// return succs[0].forward(0) != nullptr;
// }
bool has_value() { return succs[0] != nullptr; }

View File

@ -0,0 +1,225 @@
#pragma once
#include <atomic>
template <class T>
static T *load(std::atomic<T *> &atomic)
{
return atomic.load(std::memory_order_acquire())
}
template <class T>
static void store(std::atomic<T *> &atomic, T *desired)
{ // Maybe could be relaxed
atomic.store(desired, std::memory_order_release());
}
template <class T>
static bool cas(std::atomic<T *> &atomic, T *expected, T *desired)
{ // Could be relaxed must be atleast Release.
return atomic.compare_exchange_strong(expected,desired,std::memory_order_seq_cst()));
}
template <class T>
static T *swap(std::atomic<T *> &atomic, T *desired)
{ // Could be relaxed
return atomic.exchange(desired,std::memory_order_seq_cst()));
}
template <class T>
class List
{
class Node
{
friend class Iterator;
private:
Node(const T &data) : data(data) {}
Node(T &&data) : data(std::forward(data)) {}
T data;
std::atomic<Node *> next{nullptr};
std::atomic<Node *> next_rem{nullptr};
std::atomic<bool> removed{false};
};
class Iterator
{
friend class List;
Iterator() : list(nullptr), curr(nullptr) {}
Iterator(List *list) : list(list)
{
list->count++;
reset();
}
public:
Iterator(const Accessor &) = delete;
Iterator(Iterator &&other)
: list(other.list), curr(other.curr), prev(other.prev)
{
other.list = nullptr;
other.curr = nullptr;
}
~Iterator()
{
if (list == nullptr) {
return;
}
auto head_rem = load(list->head_rem);
// Fetch could be relaxed
// There exist possibility that no one will delete garbage at this
// time.
if (list.count.fetch_sub(1) == 1 && head_rem != nullptr &&
cas(list->head_rem, head_rem,
nullptr)) { // I am the last one and there is garbage to be
// removed.
auto now = head_rem;
do {
auto next = load(now->next_rem);
delete now;
now = next;
} while (now != nullptr);
}
}
T &operator*()
{
assert(valid());
return *curr;
}
T *operator->()
{
assert(valid());
return curr;
}
operator T *()
{
assert(valid());
return curr;
}
bool valid() { return curr != nullptr; }
Iterator &operator++()
{
assert(valid());
do {
prev = curr;
curr = load(curr->next);
} while (valid() && is_removed());
return this;
}
bool is_removed()
{
assert(valid());
return load(curr->removed);
}
// Returns iterator to begining
void reset()
{
prev = nullptr;
curr = load(list->head);
while (valid() && is_removed()) {
this ++;
}
}
// Adds to the begining of list
void push(T &&data)
{
auto node = new Node(data);
auto next = nullptr;
do {
next = load(list->head);
store(next.next, next);
} while (!cas(list->head, next, node));
}
// True only if this call removed the element.
bool remove()
{
assert(valid());
if (cas(curr->removed, false, true)) {
if (!disconnect()) {
find_and_disconnect();
}
store(curr->next_rem, swap(list->removed, curr));
return true;
}
return false;
}
friend bool operator==(const Iterator &a, const Iterator &b)
{
return a->curr == b->curr;
}
friend bool operator!=(const Iterator &a, const Iterator &b)
{
return !(a == b);
}
private:
void find_and_disconnect()
{
auto it = Iterator(list);
auto next = load(curr->next);
while (it.valid()) {
if (it.succ == succ) {
if (it.disconnect()) {
return;
}
it.reset();
} else if (it.succ == next) { // Comparison with next is
// optimization for early return.
return;
} else {
it++;
}
}
}
bool disconnect()
{
auto next = load(curr->next);
if (prev != nullptr) {
store(prev->next, next);
if (load(prev->removed)) {
return false;
}
} else if (!cas(list->head, curr, next)) {
return false;
}
return true;
}
List *list;
Node *prev{nullptr};
Node *curr;
};
public:
List() = default;
List(List &) = delete;
List(List &&) = delete;
void operator=(List &) = delete;
Iterator begin() { return Iterator(this); }
Iterator end() { return Iterator(); }
private:
std::atomic<size_t> count{0};
std::atomic<Node *> head{nullptr};
std::atomic<Node *> removed{nullptr};
}