带有引用计数的无锁堆栈

[英]Lock-free stack with reference counting


From answers to my previous question: Pointers in c++ after delete

从我上一个问题的答案:删除后的c ++中的指针

it's become clear, that using the values of pointers, that point to "deleted" memory (in particular, copying them) lead to undef behaviour in c++11, and implementation-defined behaviour in c++14.

很明显,使用指针的值,指向“删除”的内存(特别是复制它们)会导致c ++ 11中的undef行为,以及c ++ 14中的实现定义行为。

Antomy Williams in his book "C++ concurrency in action" suggests the next lock-free stack with reference counting:

Antomy Williams在他的书“C ++并发行动”中建议使用引用计数的下一个无锁堆栈:

#include <atomic>
#include <memory>

template<typename T>
class lock_free_stack
{
private:
    struct node;
    struct counted_node_ptr
    {
        int external_count;
        node* ptr;
    };
    struct node
    {
        std::shared_ptr<T> data;
        std::atomic<int> internal_count;
        counted_node_ptr next;
        node(T const& data_):
            data(std::make_shared<T>(data_)),
            internal_count(0)
        {}
    };
    std::atomic<counted_node_ptr> head;
    void increase_head_count(counted_node_ptr& old_counter)
    {
        counted_node_ptr new_counter;
        do
        {
            new_counter=old_counter;
            ++new_counter.external_count;
        }
        while(!head.compare_exchange_strong(
                  old_counter,new_counter,
                  std::memory_order_acquire,
                  std::memory_order_relaxed));
        old_counter.external_count=new_counter.external_count;
    }
public:
    ~lock_free_stack()
    {
        while(pop());
    }
    void push(T const& data)
    {
        counted_node_ptr new_node;
        new_node.ptr=new node(data);
        new_node.external_count=1;
        new_node.ptr->next=head.load(std::memory_order_relaxed)
            while(!head.compare_exchange_weak(
                      new_node.ptr->next,new_node,
                      std::memory_order_release,
                      std::memory_order_relaxed));
    }
    std::shared_ptr<T> pop()
    {
        counted_node_ptr old_head=
            head.load(std::memory_order_relaxed);
        for(;;)
        {
            increase_head_count(old_head);
            node* const ptr=old_head.ptr;
            if(!ptr)
            {
                return std::shared_ptr<T>();
            }
            if(head.compare_exchange_strong(
                   old_head,ptr->next,std::memory_order_relaxed))
            {
                std::shared_ptr<T> res;
                res.swap(ptr->data);
                int const count_increase=old_head.external_count-2;
                if(ptr->internal_count.fetch_add(
                       count_increase,std::memory_order_release)==-count_increase)
                {
                    delete ptr;
                }
                return res;
            }
            else if(ptr->internal_count.fetch_add(
                        -1,std::memory_order_relaxed)==1)
            {
                ptr->internal_count.load(std::memory_order_acquire);
                delete ptr;
            }
        }
    }
};

I'm worried about function

我很担心功能

void increase_head_count(counted_node_ptr& old_counter)
{
    counted_node_ptr new_counter;
    do
    {
        new_counter=old_counter;
        ++new_counter.external_count;
    }
    while(!head.compare_exchange_strong(
              old_counter,new_counter,
              std::memory_order_acquire,
              std::memory_order_relaxed));
    old_counter.external_count=new_counter.external_count;
}

It seems, that new_counter=old_counter; can be executed, when old_counter.ptr has been deleted by another thread.

看来,new_counter = old_counter;当old_counter.ptr被另一个线程删除时,可以执行。

So, could somebody confirm or refuse, that this stack implementation is strictly incorrect in c++11?

那么,有人可以确认或拒绝,这个堆栈实现在c ++ 11中是严格错误的吗?

1 个解决方案

#1


0  

It is possible, but not problematic, because the compare_exchange call will detect it and discard new_counter.

这是可能的,但不是问题,因为compare_exchange调用将检测它并丢弃new_counter。

智能推荐

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.itdaan.com/blog/2017/05/25/72009a33b2769b39d67ec3ebf640e2d7.html



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告