8

我有一个ConcurrentQueue基于用户提供的容器的类,该容器具有这样的构造函数...

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.m_Queue) {}

但是,我需要other在复制它时锁定它的互斥锁。

选项1:

所以我根本不能使用复制构造函数,并且做......

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.m_Queue)
{
    std::lock_guard<std::mutex> lock(other.m_Mutex);
    m_Queue = other.m_Queue;
}

但我不能保证复制分配和复制构造是等效的功能。

选项 2:

我可以有一个私有方法...

std::queue<T, Container> GetQueue() const
{
    std::lock_guard<std::mutex> lock(other.m_Mutex);
    return m_Queue;
}

然后在构造函数中执行此操作...

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.GetQueue()) {}

但这可能(取决于优化)使用一次 m_Queue 的复制构造函数,它是一次移动构造函数。而且我也不能保证一个副本和一个招式就等于只是一个副本。此外,用户提供的容器可能很奇怪,可以复制但不可移动,这也会导致这种方法出现问题。

那么,我该怎么办?

4

2 回答 2

9
ConcurrrentQueue::ConcurrrentQueue(
        ConcurrrentQueue const& other )
    : m_Queue( (std::lock_guard<std::mutex>( other.m_Mutex ),
               other.m_Queue ) )
{
}

应该管用。

于 2013-04-24T16:15:16.793 回答
1

锁定,创建内容的副本,然后与成员交换。至少这是最简单和恕我直言最干净的方式。另一种不太干净的方法是使用逗号运算符:(a, b)yield b,但如果a是作用域锁,则临时锁将一直存在到下一个序列点,即直到您用于b初始化本地副本。

也就是说,有两件事需要考虑:

  • 无论如何,复制可能不是一个聪明的主意,如果您禁用复制,您的设计也可以正常工作。
  • 如果您可以访问队列并且可以读取它以进行复制,这是否意味着互斥锁必须已经被锁定?如果不是,您如何确定您真的要复制队列?我不怀疑是否有证明设计合理的答案,但这很不寻常。
于 2013-04-24T16:17:14.157 回答