较之之前的使用引用计数来实现stack不同,因为queue涉及的两个操作分别对应于head tail指针
所以应该设置一个__m_external_count
这在__node节点中 它被初始化为2,只有当tail head 访问时才减去它,分别对应之后的函数__free_external_count
因此如果简单的使用前面的技术来设计lock_free算法就不再适合,因为有可能会出现这种情况:
tail指针离开其指向的节点之后,其他线程释放了这个节点,但是head指针还没有访问这个节点,
于是乎,之后如果有人调用pop。便会undefined behavior所以应该设置一个__m_external_count
这在__node节点中 它被初始化为2,只有当tail head 访问时才减去它,分别对应之后的函数__free_external_count
具体要理解话,请阅读本章stack的实现,你便会了解我的意思(以上均为本人心得,同是初学者,可能理解有偏差,具体读者可以参考这本书的内容,
有疑问也可以留言 邮箱 1355425625@qq.com)
#include <iostream>
#include <atomic>
#include <memory>
#include <thread>
#include <future>
#if defined _DEBUG
#include <crtdbg.h>
#define __MEMORY__LEAK__CHECK__ _CrtSetDbgFlag( \
_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | \
_CRTDBG_LEAK_CHECK_DF);
#define __leak__check__ __MEMORY__LEAK__CHECK__
#endif
namespace stc{
template <typename _Ty>
struct __node;
template <typename _Ty>
struct __count_node{
typedef typename __node<_Ty>* __node_pointer;
int __m_external_count;
__node_pointer __m_src;
/**data member*/
/**the consructor*/
__count_node() :__m_external_count(0),
__m_src(NULL){}
};
/**
* 较之之前的使用引用计数来实现stack不同,因为queue涉及的两个操作分别对应于head tail指针
* 因此如果简单的使用前几章的技术,有可能会出现这种情况:
* tail指针离开其指向的节点之后,其他线程释放了这个节点,但是head指针还没有访问这个节点,
* 于是乎,之后如果有人调用pop。便会undefined behavior
* 所以应该设置一个__m_external_count
* 这在__node节点中 它被初始化为2,只有当tail head 访问时才减去它,分别对应之后的函数__free_external_count
* 具体要理解话,请阅读本章stack的实现,你便会了解我的意思
*/
struct __inside_counter{
int __m_internal_count : 30;
unsigned int __m_external_count : 2;
};/**the inside counter */
template <typename _Ty>
struct __node{
typedef _Ty* __pointer;
typedef _Ty& __reference;
typedef typename std::atomic<__pointer> __atomic_data_type;
typedef typename std::atomic<__count_node<_Ty>> __atomic_link_type;
typedef typename std::atomic<__inside_counter> __atomic_count_type;
__atomic_data_type __m_data;
__atomic_count_type __m_counter;
__atomic_link_type __m_next;
__node() :__m_data(NULL){
__inside_counter __counter_init;
__counter_init.__m_external_count = 2;
__counter_init.__m_internal_count = 0;
__m_counter.store(__counter_init, std::memory_order_release);
}
void __release_reference();
};
template <typename _Ty>
void __node<_Ty>::__release_reference(){
__inside_counter __o_count = __m_counter.load(std::memory_order_relaxed);
__inside_counter __n_count;
do{
__n_count = __o_count;
--__n_count.__m_internal_count;
} while (!__m_counter.compare_exchange_strong(__o_count, __n_count,
std::memory_order_acquire, std::memory_order_relaxed));
if (!__n_count.__m_external_count &&
!__n_count.__m_internal_count){
delete this;
}
}
template <typename _Ty>
class lk_free_que_s{
typedef typename __count_node<_Ty> __count_node_type;
typedef typename std::atomic<__count_node_type> __atomic_count_node_type;
public:
lk_free_que_s();
~lk_free_que_s();
std::unique_ptr<_Ty> pop();
void push(const _Ty&);
private:
static void __increase_external_count(__atomic_count_node_type&, __count_node_type&);
static void __free_external_count(__count_node_type&);
void __set_tail(__count_node_type&, __count_node_type);
void __init();
void __destroy();
void __clear();
void __reset();
__count_node_type __allocate_count_node();
private:
__atomic_count_node_type __m_head;
__atomic_count_node_type __m_tail;
};
template <typename _Ty>
lk_free_que_s<_Ty>::lk_free_que_s(){
this->__init();
}
template <typename _Ty>
lk_free_que_s<_Ty>::~lk_free_que_s(){
this->__destroy();
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__init(){
__count_node_type nil = __allocate_count_node();
try{
__m_head.store(nil, std::memory_order_release);
__m_tail.store(nil, std::memory_order_release);
}catch (...){
delete nil.__m_src;
throw;
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__destroy(){
try{
while (pop());
delete __m_tail.load().__m_src;
} catch (...){}
}
template <typename _Ty>
typename lk_free_que_s<_Ty>::__count_node_type
lk_free_que_s<_Ty>::__allocate_count_node(){
try{
std::unique_ptr<__node<_Ty>> __src(new __node<_Ty>);
__count_node_type __res;
__res.__m_external_count = 1;
__res.__m_src = __src.get();
__src.release();
return __res;
}
catch (...){ throw; }
}
/**
* 此处两个函数的作用之前已经给出
*/
template <typename _Ty>
void lk_free_que_s<_Ty>::__increase_external_count(
__atomic_count_node_type& __head, __count_node_type& __o_counter){
__count_node_type __n_counter;
do{
__n_counter = __o_counter;
++__n_counter.__m_external_count;
} while (!__head.compare_exchange_strong(__o_counter,__n_counter,
std::memory_order_acquire,std::memory_order_relaxed));
__o_counter.__m_external_count = __n_counter.__m_external_count;
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__free_external_count(__count_node_type& __o_counter){
__node<_Ty>* __src = __o_counter.__m_src;
assert(__src != NULL);
const int __count_result = __o_counter.__m_external_count - 2;
__inside_counter __o_inside_counter = __src->__m_counter.load(std::memory_order_relaxed);
__inside_counter __n_inside_counter;
do{
__n_inside_counter = __o_inside_counter;
--__n_inside_counter.__m_external_count;
__n_inside_counter.__m_internal_count += __count_result;
} while (!__src->__m_counter.compare_exchange_strong(__o_inside_counter,__n_inside_counter,
std::memory_order_acquire,std::memory_order_relaxed));
if (!__n_inside_counter.__m_external_count &&
!__n_inside_counter.__m_internal_count){
delete __src;
}
}
template <typename _Ty>
std::unique_ptr<_Ty> lk_free_que_s<_Ty>::pop(){
__count_node_type __o_head = __m_head.load(std::memory_order_relaxed);//获得头部指针
while (true){//increase count reference
__increase_external_count(__m_head, __o_head);
__node<_Ty>* __src = __o_head.__m_src;
if (__src == __m_tail.load().__m_src){//如果__m_head __m_tail都是同一个元素 自然队列中是没有元素的
__src->__release_reference();//decrease count reference
return std::unique_ptr<_Ty>();//return null pointer
}
__count_node_type __next = __src->__m_next.load();//get the next node
if (__m_head.compare_exchange_strong(__o_head, __next)){//if the head is't changed than the value of head will be the next node
std::unique_ptr<_Ty> __res(__src->__m_data.exchange(NULL));
__free_external_count(__o_head);//decrease count reference
return __res;//return the result
}
__src->__release_reference();//decrease count reference
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::push(const _Ty& __data){
std::unique_ptr<_Ty> __src(new _Ty(__data));
_Ty* __o_data = NULL;
__count_node_type __n_next = __allocate_count_node();//分配一个新的节点
__count_node_type __o_tail = __m_tail.load();//获得尾部指针
while (true){
__increase_external_count(__m_tail, __o_tail);
__o_data = NULL;//如果成功更新了数据,那么我们下一步就是跟新尾部指针 __m_tail 使之指向新分配的节点
if (__o_tail.__m_src->__m_data.compare_exchange_strong(__o_data, __src.get())){
__count_node_type __o_next;//如果没有线程帮助这个线程设置好尾部指针
//那么现在的next域应该还是默认构造函数构造出来的__count_node_type 的object
if (!__o_tail.__m_src->__m_next.compare_exchange_strong(__o_next, __n_next)){
delete __n_next.__m_src;//如果已经有线程更新了__m_tail,自然刚才从堆中分配的__node就不需要
__n_next = __o_next;//指向之后一个元素
}
__set_tail(__o_tail, __n_next);//如果没有线程帮助跟新尾部指针,那么就要调用__free_external_count
__src.release();//否则是要调用__release_reference的
return;//释放智能指针,不然它会释放堆中的内存
}else{//如果没有能跟新数据,那么就帮助其他线程跟新尾部指针 我们的宗旨就是让所有的线程都在忙碌之中
__count_node_type __o_next;
if (__o_tail.__m_src->__m_next.compare_exchange_strong(__o_next, __n_next)){
__o_next = __n_next;//如果更新成功了
__n_next.__m_src = new __node<_Ty>;//自然__n_next还要帮助当前这个线程把它要加入的__data push
}//到队列之中,所以还要重新分配__m_src
__set_tail(__o_tail, __o_next);
}
}
}
template <typename _Ty>
void lk_free_que_s<_Ty>::__set_tail(__count_node_type& __o_tail, __count_node_type __next){
__node<_Ty>* __src = __o_tail.__m_src;//保存之前的__src
__m_tail.compare_exchange_strong(__o_tail, __next);//如果对比成功了,自然是调用__free_external_count
if (__o_tail.__m_src == __src)//否则只能调用__release_reference
__free_external_count(__o_tail);
else __src->__release_reference();
}
}