C++11 - 无锁队列

无锁操作的本质依赖的原子操作,C++11提供了atomic的原子操作支持

  • atomic
  • compare_exchange_weak / compare_exchange_strong
    当前值与期望值相等时,修改当前值为设定值,返回true
    当前值与期望值不等时,将期望值修改为当前值,返回false
  • memory_order枚举值
    在这里插入图片描述
template<typename T>
class lock_free_stack
{
private:
    struct node
    {
        T data;
        node* next;
        node(T const& data_):
        data(data_)
        {
        }
    };

    std::atomic<node*> head;

public:
    void push(T const& data)
    {
        node* const new_node=new node(data);
        new_node->next=head.load();  

        /*
        ** 当前值.compare_exchange_weak(期望值, 设置值)
        ** 单线程的情况:
        ** 第一次执行while循环:
        ** 此时当前值与期望值相等,修改当前值为设定值 head = new_node,返回true
        ** 多线程的情况:
        ** 第一次执行循环体的时候:
        ** compare_exchange_weak如果失败, 返回false, 证明有其他线程更新了栈顶head,
        ** 当前值与期望值不等时,将期望值修改为当前值, 即new_node->next等于新的栈顶head,
        ** 被其他线程更新的新栈顶值会被更新到new_node->next中,
        ** 因此循环可以直接再次尝试压栈而无需由程序员更新new_node->next。
        ** 然后第二次执行循环体:
        ** 此时 head == new_node->next, 所以 head = new_node.
        ** 如果这是仍有其他线程干扰,则仍为循环更新new_node->next
        */
        while(!head.compare_exchange_weak(new_node->next,new_node));
    }
};

CAS原子操作

  • CAS即Compare and Swap,是所有CPU指令都支持CAS的原子操作(X86中CMPXCHG汇编指令),用于实现实现各种无锁(lock free)数据结构。
  • CAS用于检查一个内存位置是否包含预期值,如果包含,则把新值复赋值到内存位置。成功返回true,失败返回false。示例代码如下:
    bool compare_and_swap ( int *memory_location, int expected_value, int new_value)
    {
        if (*memory_location == expected_value)
        {
            *memory_location = new_value;
            return true;
        }
        return false;
    }
    

ABA问题

假设有两个线程——线程1和线程2,两个线程按照顺序进行以下操作:

  1. 线程1读取内存中数据为A;
  2. 线程2将该数据修改为B;
  3. 线程2将该数据修改为A;
  4. 线程1对数据进行CAS操作

在第4步中,由于内存中数据仍然为A,因此CAS操作成功,但实际上该数据已经被线程2修改过了,可能存在潜藏的问题,例如栈顶问题:一个栈的栈顶经过两次(或多次)变化又恢复了原值,但是栈可能已发生了变化。这就是ABA问题。

解决思路
对于ABA问题,比较有效的方案是引入版本号,内存中的值每发生一次变化,版本号都+1;在进行CAS操作时,不仅比较内存中的值,也会比较版本号,只有当二者都没有变化时,CAS才能执行成功。Java中的AtomicStampedReference类便是使用版本号来解决ABA问题的。

Fetch-And-Add (FAA)

一般用来对变量做+1的原子操作

Test-And-Set (TAS)

写值到某个内存位置并传回其旧值

参考文章

C++11:原子交换函数compare_exchange_weak和compare_exchange_strong

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值