implemented hazard pointer management

This commit is contained in:
Dominik Tomičević 2015-09-15 21:34:52 +02:00
parent 0c65f14043
commit 74ad181227

112
memory/hp.hpp Normal file
View File

@ -0,0 +1,112 @@
#ifndef MEMGRAPH_MEMORY_HP_HPP
#define MEMGRAPH_MEMORY_HP_HPP
#include <atomic>
#include <cassert>
#include <unistd.h>
namespace memory
{
constexpr const size_t HP_SIZE = 128;
class HP
{
public:
// this object can't be copied or moved
HP(HP&) = delete;
HP(HP&&) = delete;
// grabs a singleton instance
static HP& get()
{
static HP hp;
return hp;
}
class reference
{
friend class HP;
public:
reference(reference&) = delete;
// this type shouldn't be copyable to avoid calling its destructor
// multiple times, but should be movable
reference(reference&& other)
{
this->idx = other.idx;
// set the index to a negative number to indicate that this
// index has been moved and that you should not free its
// hazard pointer
other.idx = -1;
}
// hazard pointer is cleared once reference goes out of scope
~reference()
{
// check if this reference was moved during its lifetime
if(idx < 0)
return;
auto& hp = HP::get();
hp.clear(*this);
}
private:
reference(int64_t idx) : idx(idx) {}
int64_t idx;
};
friend class reference;
template <class T>
reference insert(T* ptr)
{
auto p = reinterpret_cast<uintptr_t>(ptr);
while(true)
{
// try to find a free spot in the hazard pointer list
for(size_t i = 0; i < HP_SIZE; ++i)
{
auto hazard = ptr_list[i].load();
// if this spot isn't free, continue searching
if(hazard != 0)
continue;
// try to take this spot, if we fail, then another thread has
// just taken it. continue searching for a new one
if(!ptr_list[i].compare_exchange_strong(hazard, p))
continue;
// found a free spot! return a reference to this spot so it
// can be cleared later
return reference(i);
}
// we didn't find any free spots, sleep for a while and try again
// from the beginning, some other thread might have freed a spot
// while we were traversing the lsit.
usleep(250);
}
}
private:
HP()
{
for(size_t i = 0; i < HP_SIZE; ++i)
ptr_list[i].store(0);
}
void clear(reference& ref)
{
ptr_list[ref.idx].store(0);
}
std::atomic<uintptr_t> ptr_list[HP_SIZE];
};
}
#endif