使用危险指针的无锁栈

/*************************************************************************
> 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值