【问题标题】:C++11 lockless queue using std::atomic (multi writer, single consumer)使用 std::atomic 的 C++11 无锁队列(多写者,单消费者)
【发布时间】:2013-12-20 18:57:14
【问题描述】:

我使用 C++11 中的新 std::atomic 生成了无锁(无锁)队列的简单实现。我在这里看不到我做错了什么。

#include <atomic>

template<typename T>
class lockless_queue
{
public:
    template<typename DataType>
    struct node
    {
        node(const DataType& data)
          : data(data), next(nullptr) {}
        DataType data;
        node* next;
    };

    lockless_queue()
      : head_(nullptr) {}

    void produce(const T &data)
    {
        node<T>* new_node = new node<T>(data);
        // put the current value of head into new_node->next
        new_node->next = head_.load(std::memory_order_relaxed);
        // now make new_node the new head, but if the head
        // is no longer what's stored in new_node->next
        // (some other thread must have inserted a node just now)
        // then put that new head into new_node->next and try again
        while(!std::atomic_compare_exchange_weak_explicit(
            &head_,
            &new_node->next,
            new_node,
            std::memory_order_release,
            std::memory_order_relaxed)) {}
    }

    node<T>* consume_all()
    {
        // Reset queue and return head atomically
        return head_.exchange(nullptr, std::memory_order_consume);
    }
private:
    std::atomic<node<T>*> head_;
};

// main.cpp
#include <iostream>

int main()
{
    lockless_queue<int> s;
    s.produce(1);
    s.produce(2);
    s.produce(3);
    auto head = s.consume_all();
    while (head)
    {
        auto tmp = head->next;
        std::cout << tmp->data << std::endl;
        delete head;
        head = tmp;
    }
}

我的输出:

2
1
Segmentation fault (core dumped)

我能否提供一些在哪里查看的指示或指示我可能做错了什么?

谢谢!

【问题讨论】:

  • 以防万一你不知道(不建议你放弃你的努力),但 boost 有一个无锁队列。 boost.org/doc/libs/1_53_0/doc/html/boost/lockfree/queue.html
  • 您正在推动三个项目,然后在一个线程中依次弹出它们。为什么不能调试这个?如果你不能用一个线程解决它并且没有争用,我对多个生产者和一个消费者不抱太大希望。

标签: c++ multithreading c++11 atomic lock-free


【解决方案1】:

您正在取消引用 tmp 而不是 head

while (head)
    {
        auto tmp = head->next;
        std::cout << tmp->data << std::endl;
        delete head;
        head = tmp;
    }

应该是:

while (head)
    {
        std::cout << head->data << std::endl;
        auto tmp = head->next;
        delete head;
        head = tmp;
    }

这就是为什么3 不出现在您的输出中而Segmentation fault 出现的原因。

【讨论】:

    【解决方案2】:

    在您开始尝试执行并发入队之前,您的代码中有另一个错误不会出现。如果您的compare_exchange_weak_explicit 失败,这意味着另一个线程设法更改了head 指针,因此在您再次尝试您的CAS 之前,您需要将head 指针的新值重新加载到您的@ 987654324@。以下方法可以解决问题:

        while(!std::atomic_compare_exchange_weak_explicit(
            &head_,
            &new_node->next,
            new_node,
            std::memory_order_release,
            std::memory_order_relaxed)) {
            new_node->next = head_.load(std::memory_order_relaxed);
        }
    

    【讨论】:

    • 其实不是。如果失败,std::atomic_compare_exchange 会将预期值更新为实际值。这是否是理想的功能值得商榷。无论如何,您甚至可能想自己做。但是std::atomic_compare_exchange 会为你做这件事。
    猜你喜欢
    • 2014-10-31
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 2011-08-30
    相关资源
    最近更新 更多