首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发队列

并发队列
EN

Code Review用户
提问于 2014-06-04 22:31:27
回答 1查看 590关注 0票数 7

最近,我编写了一个并发的、没有互斥锁(但不是无锁的)队列,并想知道它是否真的正确,以及是否有什么特别的改进可以做:

代码语言:javascript
复制
template <typename T>
class concurrent_queue
{
protected:
    T *storage;
    std::size_t s;
    std::atomic<T*> consumer_head, producer_head;

    union alignas(16) dpointer
    {
        struct
        {
            T *ptr;
            std::size_t cnt;
        };
        __int128 val;
    };

    dpointer consumer_pending, producer_pending;

public:
    concurrent_queue(std::size_t s): storage(nullptr)
    {
        storage = static_cast<T*>(::operator new((s+1)*sizeof(T)));

        consumer_head = storage;
        __atomic_store_n(&(consumer_pending.val), (dpointer{storage, 0}).val, __ATOMIC_SEQ_CST);

        producer_head = storage;

        __atomic_store_n(&(producer_pending.val), (dpointer{storage, 0}).val, __ATOMIC_SEQ_CST);
        this->s = s + 1;
    }
    ~concurrent_queue()
    {
        while(consumer_head != producer_head)
        {
            ((T*)consumer_head)->~T();
            ++consumer_head;
            if(consumer_head == storage + s)
                consumer_head = storage;
        }
        ::operator delete(storage);
    }

    template <typename U>
    bool push(U&& e)
    {
        while(true)
        {
            dpointer a;
            a.val = __atomic_load_n(&(producer_pending.val), __ATOMIC_ACQUIRE);
            auto b = consumer_head.load(std::memory_order_relaxed);
            auto next = a.ptr + 1;
            if(next == storage + s) next = storage;

            if(next == b) return false;
            dpointer newval{next, a.cnt+1};
            if(!__atomic_compare_exchange_n(&(producer_pending.val), &(a.val), (newval.val), true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) continue;

            new (a.ptr) T(std::forward<U>(e));

            while(!producer_head.compare_exchange_weak(a.ptr, next, std::memory_order_release, std::memory_order_relaxed));
            return true;
        }
    }

    template <typename U>
    bool pop(U& result)
    {
        while(true)
        {
            dpointer a;
            a.val = __atomic_load_n(&(consumer_pending.val), __ATOMIC_ACQUIRE);
            auto b = producer_head.load(std::memory_order_relaxed);
            auto next = a.ptr + 1;
            if(next == storage + s) next = storage;

            if(a.ptr == b) return false;
            dpointer newval{next, a.cnt+1};
            if(!__atomic_compare_exchange_n(&(consumer_pending.val), &(a.val), (newval.val), true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) continue;

            result = std::move(*(a.ptr));
            (a.ptr)->~T();

            while(!consumer_head.compare_exchange_weak(a.ptr, next, std::memory_order_release, std::memory_order_relaxed));
            return true;
        }
    }
};

这是一个特定于GCC的x86_64平台和一个支持双宽度CAS的CPU,但我想对其他平台进行调整并不难。

我强调用多线程推送和弹出式测试它,使用POD类型和内存管理类型(如std::vector ),并且没有任何问题,所以我把far...before放在双宽度的far...before中,我遇到了far...before问题,并且有分割错误,但是它似乎很好。

然而,我对所有这些多线程的东西都是新手,我希望有一个比我更有经验的人告诉我,这个方法是否能在一个内存模型薄弱的系统上工作。

EN

回答 1

Code Review用户

回答已采纳

发布于 2014-12-20 17:28:18

对于push()pop()中的条件返回类型,使用不同类型的无限循环(如for(;;) )可能会更清楚。这将更好地将注意力集中在循环内容上。

您也可以为单行语句使用大括号。其中一些行相当长,因此执行的代码处于末尾。这也应该有助于区分他们和繁忙的等待。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/52481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档