队列<T>上的原子操作?

Posted

技术标签:

【中文标题】队列<T>上的原子操作?【英文标题】:Atomic operation on queue<T>? 【发布时间】:2015-08-26 12:57:53 【问题描述】:

我应该在 Visual C++ 中实现一个带有队列的类;在这个队列中我要做原子操作。在网上搜索,我找到了 std::atomic 类,但我保留了一些问题。第一个是:有什么区别:

A)atomic &lt;queue &lt;T&gt;&gt; fifo;

B)queue &lt;atomic &lt;T&gt;&gt; fifo; ?

第二个问题是:如何进行push这样的原子操作?

push (T.load) 

是正确的解决方案吗?

最后一个问题是:如果我用互斥锁保护队列上的某些操作,我还需要对其进行原子操作吗?

感谢您的任何建议,问候

【问题讨论】:

您究竟需要什么样的雾化?什么需要是原子? 编写正确的原子队列非常困难。世界级的专家在这方面失败了。你知道你是否有单一的生产者 - 单一的消费者吗?单个生产者 - 多个消费者?多个生产者 - 单个消费者?多个生产者 - 多个消费者?这些是具有不同要求的不同案例。 当你说原子时,我想到了无锁。如果您只是在 poppush 函数的开头获得一个互斥锁,那么您应该很好。 在 Windows 上,您可以使用 PPL 标头和 concurrent_* 容器来实现线程安全的标准库。 在你的上下文中,原子可能意味着“队列上的操作是不可分割的”——队列上的事情可以在给定的原子操作之前或之后发生,但不能重叠或发生在中间。 【参考方案1】:

A) atomic&lt;queue &lt;T&gt;&gt; fifo; 甚至不会编译,因为 std::atomic 需要一个可简单复制的类型

B) 将执行 T 类型的原子读取或写入,但使用队列(推送或弹出)的操作将不是原子的。

您需要使用mutex 保护queue 操作:

template<typename T>
class my_queue

public:
    void push( const T& value )
    
        std::lock_guard<std::mutex> lock(m_mutex);
        m_queque.push(value);
    

    void pop()
    
        std::lock_guard<std::mutex> lock(m_mutex);
        m_queque.pop();
    

private:
    std::queue<T> m_queque;
    mutable std::mutex m_mutex;
;

【讨论】:

感谢您的回答。所以,在您看来,“插入和删除操作应该是原子的”这句话与“用互斥锁保护操作”是一样的吗? 如果你用互斥锁保护操作,操作将是原子的。在我的答案中添加了一个示例类。

以上是关于队列<T>上的原子操作?的主要内容,如果未能解决你的问题,请参考以下文章

RFO计入英特尔CPU上的原子添加操作和缓存线锁定?

Lockfree堆栈与原子

原子操作实现无锁队列

C++ 原子操作 std::atomic<int>

CAS无锁队列与线程同步

Linux设备驱动程序 之 原子操作