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