/*************************************************************************
> File Name: hazard_pointer_lockfreestack.cpp
> Author:
> Mail:
> Created Time: Wed 01 Aug 2018 08:33:29 PM CST
************************************************************************/
#include<iostream>
#include <atomic>
#include <thread>
#include <memory>
//数组数目
const int max_hazard_point = 100;
struct hazard_pointer
{
std::atomic<std::thread::id> id;
std::atomic<void*> pointer;
};
hazard_pointer hazard_pointers[max_hazard_point];
//危险指针存储类
class hp_owner
{
public:
hp_owner() :hp(NULL)
{
for (int i = 0; i < max_hazard_point; ++i)
{
std::thread::id old_id;
if (hazard_pointers[i].id.compare_exchange_strong(old_id, std::this_thread::get_id()))
{
hp = &hazard_pointers[i];
break;
}
}
}
virtual ~hp_owner()
{
hp->id.store(std::thread::id());
hp->pointer.store(NULL);
}
std::atomic<void*>& GetPointer()
{
return hp->pointer;
}
hp_owner(const hp_owner&) = delete;
hp_owner operator=(const hp_owner&) = delete;
private:
hazard_pointer * hp;
};
//为线程分配危险指针存储空间
std::atomic<void*>& get_hazard_pointer_for_current_thread()
{
static hp_owner hp;
return hp.GetPointer();
}
//判断当前指针是否被使用
bool outstanding_hazard_pointer_for(void* p)
{
for (int i = 0; i < max_hazard_point; ++i)
{
if (hazard_pointers[i].pointer.load() == p)
{
return true;
}
}
return false;
}
template <class T>
void delete_node(void* p)
{
delete static_cast<T*>(p);
}
//数据回收存储结构
struct data_to_reclaim
{
void* data;
std::function<void(void*)> deleter;
data_to_reclaim* next;
template<typename T>
data_to_reclaim(T* p) :data(p),
deleter(&delete_node<T>),
next(NULL)
{
}
~data_to_reclaim()
{
deleter(data);
}
};
std::atomic<data_to_reclaim*> nodes_to_reclaim;
//将数据加入回收链表
void add_to_reclaim_list(data_to_reclaim* dta)
{
if (!dta)
{
return;
}
dta->next = nodes_to_reclaim;
while (!nodes_to_reclaim.compare_exchange_weak(dta->next, dta));
}
//将数据封装后加入回收链表
template<typename T>
void reclaim_later(T* dta)
{
add_to_reclaim_list(new data_to_reclaim(dta));
}
//删除待回收数据
void delete_node_with_no_hazard()
{
data_to_reclaim* node = nodes_to_reclaim.exchange(NULL);
while (node)
{
data_to_reclaim* next = node->next;
if (!outstanding_hazard_pointer_for(node->data))
{
delete node;
}
else {
add_to_reclaim_list(node);
}
node = next;
}
}
//无锁栈实现
template<class T>
class LockFreeStack
{
struct Node {
Node(T dta)
{
node = std::make_shared<T>(dta);
}
std::shared_ptr<T> node;
Node* next;
};
public:
LockFreeStack() { head = NULL; }
virtual ~LockFreeStack() {}
void Push(T dta)
{
Node* node_dta = new Node(dta);
node_dta->next = head;
while (node_dta && !head.compare_exchange_weak(node_dta->next, node_dta));
}
std::shared_ptr<T> Pop()
{
std::atomic<void*>& hp = get_hazard_pointer_for_current_thread();
Node* old_node = head.load();
do {
Node* tmp;
do {
tmp = old_node;
hp.store(old_node);
old_node = head.load();
} while (tmp != old_node);
} while (old_node && !head.compare_exchange_strong(old_node, old_node->next));
hp.store(NULL);
std::shared_ptr<T> res;
if (old_node)
{
res.swap(old_node->node);
if (outstanding_hazard_pointer_for(old_node))
{
reclaim_later(old_node);
}
else
{
delete old_node;
}
delete_node_with_no_hazard();
}
return res;
}
private:
std::atomic<Node*> head;
std::atomic<Node*> node_to_be_delete;
};
LockFreeStack<int> stack;
void PushStackI()
{
for (int i = 0; i < 10; ++i)
{
stack.Push(i);
}
}
void PushStackJ()
{
for (int i = 20; i < 30; ++i)
{
stack.Push(i);
}
}
void PopStack()
{
while (1)
{
std::shared_ptr<int> ptr = stack.Pop();
if (ptr)
std::cout << *ptr << std::endl;
}
}
int main()
{
std::thread t1(PushStackI);
std::thread t2(PushStackJ);
std::thread t3(PopStack);
t1.join();
t2.join();
t3.join();
return 0;
}