2013-04-24 67 views
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的复制构造函数一次,并且它只是移动构造函数一次。而且我也不能保证副本和移动只相当于副本。此外,用户提供的容器可能是奇怪的,可复制但不可移动,这也会导致这种方法有问题。

那么,我该怎么办?

回答

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

应该工作。

+0

你认为应该总是这样做吗? – 0x499602D2 2013-04-24 22:14:51

+0

@ 0x499602D2其实,我认为应该避免这种情况。我不太了解你的实际情况,或者你正在尝试解决的问题,并提出其他解决方案,但我知道我从来没有真正使用过这样的东西。事实上,我无法真正想到在线程之间复制容器的情况。 – 2013-04-24 23:07:47

1

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

这就是说,都需要考虑两件事情:

  • 也许,不能复制反正这样一个聪明的想法和你的设计作品,以及如果你只是不能进行复印。
  • 如果您有权访问队列并且可以读取它进行复制,那么这是不是意味着互斥锁必须已被锁定?如果不是,你怎么确定你真的想复制队列?我不怀疑有什么答案可以证明设计的合理性,但这是不寻常的。