Skip to content

Instantly share code, notes, and snippets.

@zesterer
Created August 29, 2017 10:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zesterer/b6f7a685ee2a33e8fd4b28fe57e5d170 to your computer and use it in GitHub Desktop.
Save zesterer/b6f7a685ee2a33e8fd4b28fe57e5d170 to your computer and use it in GitHub Desktop.
Thread-safe reference-based object bucket in C++
#include <iostream>
#include <mutex>
#include <unordered_map>
namespace PtrTest
{
/* Definitions */
typedef long id_t;
const id_t ID_INVALID = -1;
template <typename T>
class table_t;
template <typename T, table_t<T>& CONTAINER>
class ptr_t;
template <typename T>
class table_t
{
private:
struct _item_t
{
T* _item = nullptr;
std::mutex _mut;
_item_t() {}
_item_t(T* item) : _item(item) {}
};
std::unordered_map<id_t, _item_t> _items;
id_t _id_count;
std::mutex _mut;
id_t _new_id() { return ++this->_id_count; }
public:
T* get(id_t id)
{
this->_mut.lock(); // Begin critical section
T* val = this->_items[id]._item;
this->_mut.unlock(); // End critical section
return val;
}
id_t add(T* item)
{
this->_mut.lock(); // Begin critical section
id_t id = this->_new_id();
this->_items.emplace(id, item);
this->_mut.unlock(); // End critical section
return id;
}
void lock(id_t id)
{
this->_mut.lock(); // Begin critical section
this->_items[id]._mut.lock();
this->_mut.unlock(); // End critical section
}
void unlock(id_t id)
{
this->_mut.lock(); // Begin critical section
this->_items[id]._mut.unlock();
this->_mut.unlock(); // End critical section
}
template <table_t<T>& table, typename ... Args>
ptr_t<T, table> create(Args ... args)
{
return this->add(new T(args...));
}
};
template <typename T, table_t<T>& CONTAINER>
class ptr_t
{
private:
id_t _id;
public:
class _proxy_t
{
private:
id_t _id;
T* _item;
public:
_proxy_t(id_t id, T* item) : _id(id), _item(item)
{
CONTAINER.lock(_id);
}
T* operator->() { return this->_item; }
~_proxy_t()
{
CONTAINER.unlock(_id);
}
};
ptr_t(id_t id)
{
this->_id = id;
}
ptr_t(T* item)
{
this->_id = CONTAINER.add(item);
}
void lock()
{
CONTAINER.lock(this->_id);
}
void unlock()
{
CONTAINER.unlock(this->_id);
}
_proxy_t operator->() { return _proxy_t(this->_id, CONTAINER.get(this->_id)); }
};
}
/* Application */
struct Number
{
int num;
Number(int n) : num(n) {}
void say() { std::cout << "The number is " << this->num << std::endl; }
};
PtrTest::table_t<Number> table;
int main()
{
auto ptr1 = table.create<table>(7);
auto ptr2 = table.create<table>(1337);
auto ptr3 = table.create<table>(42);
auto ptr4 = ptr2;
ptr1->say();
ptr2->say();
ptr3->say();
ptr4->say();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment