c++11記憶體模型以及引用計數無鎖棧的實現
c++11提供了6中記憶體模型:
memory_order_seq_cst(原子操作預設模型)
memory_order_relaxed (沒有順序性的要求
memory_order_release
memory_order_acquire
memory_order_consume
memory_order_acq_rel
提供記憶體模型,記憶體屏障主要是為了解決,編譯器指令重排和快取一致性的問題。
其中memory_order_seq_cst提供了最強的約束,要求多處理器中的操作在所有執行緒中可見,並要求所有執行緒中的執行順序一致。
memory_order_relaxed 沒有執行緒間執行順序的要求,只提供原子操作。
memory_order_release和memory_order_acquire ,指定了順序性要求,其中store語義中使用memory_order_release,load語義中使用memory_order_acquire,可以實現操作的同步性。
memory_order_release和memory_order_consume,指定了順序性要求,但是約束性比memory_order_release和memory_order_acquire要低,只要求相關性同步,其中store語義中使用memory_order_release,load語義中使用memory_order_consume,可以實現操作的同步性。
memory_order_acq_rel一般用在read_modify_write語義中,上面承接memory_order_release語義,本身在進入時有memory_order_acquire語義,操作結束後使用memory_order_release語義,下面承接memory_order_acquire語義。
下面是使用release和acquire語義實現的無鎖引用計數棧
/************************************************************************* > File Name: reference_count_lockfreestack.cpp > Author: > Mail: > Created Time: Thu 02 Aug 2018 08:30:54 PM CST ************************************************************************/ #include<iostream> #include <atomic> #include <memory> #include <thread> template<class T> class LockFreeStack { private: struct CountNodePtr; public: LockFreeStack() { } ~LockFreeStack() { } //LockFreeStack(const LockFreeStack&) = delete; //LockFreeStack operator=(const LockFreeStack&) = delete; void Push( T dta ) { CountNodePtr node; node.external_count = 1; node.ptr = new Node(dta); node.ptr->next = head.load(std::memory_order_relaxed); while( !head.compare_exchange_weak( node.ptr->next, node, std::memory_order_release) ); } std::shared_ptr<T> Pop() { CountNodePtr node = head.load(); while(1) { IncreateHeadCount(node); Node* ptr = node.ptr; if( !ptr ) { return std::shared_ptr<T>(); } if( head.compare_exchange_strong(node, ptr->next, std::memory_order_relaxed) ) { std::shared_ptr<T> res; res.swap( ptr->dta ); const int count = node.external_count - 2; if( node.ptr->internal_count.fetch_add(count, std::memory_order_release) == -count ) { delete ptr; } return res; } else if( ptr->internal_count.fetch_sub(1, std::memory_order_relaxed) == 0 ) { ptr->internal_count.load(std::memory_order_acquire); delete ptr; } } } private: void IncreateHeadCount( CountNodePtr& node) { CountNodePtr new_node; do { new_node = node; ++new_node.external_count; } while( !head.compare_exchange_strong( node, new_node, std::memory_order_acquire) ); node.external_count = new_node.external_count; } private: struct Node; struct CountNodePtr { int external_count; Node* ptr; }; struct Node { std::atomic<int> internal_count; std::shared_ptr<T> dta; CountNodePtr next; Node( T dta ): dta( std::make_shared<T>(dta) ), internal_count(0) { } }; std::atomic<CountNodePtr> head; }; 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; }