Re: Atomics в gcc 4.6 в c++0x
От: TarasKo Голландия  
Дата: 14.05.11 21:47
Оценка:
Вот та реализация lock-free стека которая падает у меня.
Кстати если закомментировать строчки выделеные жирным, то падать перестаёт.
Ну и разумеется для воспроизведения падения, необходимо что бы pop вызывали несколько потоков.

template<typename T>
class lf_stack_pop_dummy_guard
{
public:
    lf_stack_pop_dummy_guard() : 
        head_(0), threads_in_pop_(0), to_be_deleted_(0)
    {}
    
    lf_stack_pop_dummy_guard(const lf_stack_pop_dummy_guard&) = delete;
    lf_stack_pop_dummy_guard& operator=(const lf_stack_pop_dummy_guard&) = delete;

    ~lf_stack_pop_dummy_guard()
    {
        node* head = head_.load(std::memory_order_relaxed);
        while(head) 
        {
            node* old_head = head;
            head = head->next_;
            delete old_head;
        }
    }

    void push(const T& val)
    {
        node* const new_node = new node(val);
        new_node->next_ = head_.load();
        while(!head_.compare_exchange_weak(new_node->next_, new_node));
    }
    
    std::shared_ptr<T> pop()
    {
        ++threads_in_pop_;
        
        node* old_head = head_.load();
        while(old_head && !head_.compare_exchange_strong(old_head, old_head->next_));

        std::shared_ptr<T> res;
        if (old_head)
            res.swap(old_head->data_);
                
        node* nodes_to_delete = to_be_deleted_.load();
        
        if (!--threads_in_pop_)
        {
            if (to_be_deleted_.compare_exchange_strong(nodes_to_delete, 0))  
                delete_nodes(nodes_to_delete);
            
            delete old_head; 
        }
        else if (old_head)
        {
            old_head->next_ = nodes_to_delete;
            while(!to_be_deleted_.compare_exchange_weak(old_head->next_, old_head)); 
        }
        
        return res;
    }

private:
    struct node 
    {
        node(const T& data) : data_(new T(data)), next_(0) {}
        
        node() = delete;
        node(const node&) = delete;
        node& operator=(const node&) = delete;
        
        std::shared_ptr<T> data_;
        node* next_;
    };

    static void delete_nodes(node* head)
    {
        while(head)
        {
            node* next = head->next_;
            delete head;
            head = next;
        }
    }
    
    std::atomic<node*> head_;
    std::atomic<unsigned> threads_in_pop_;
    std::atomic<node*> to_be_deleted_;
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.