因此如果简单的使用前面的技术来设计lock_free算法就不再适合,因为有可能会出现这种情况:
tail指针离开其指向的节点之后,其他线程释放了这个节点,但是head指针还没有访问这个节点,
于是乎,之后如果有人调用pop。便会undefined behavior具体要理解话,请阅读本章stack的实现,你便会了解我的意思(以上均为本人心得,同是初学者,可能理解有偏差,具体读者可以参考这本书的内容,
有疑问也可以留言 邮箱 [email protected])
#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(); } }