0

我有点意识到这不是一个问题,而是一个讨论,但我相信可以提供一个或多个答案,所以你去吧。

我有这样的课

class MyAwesomeObject {
public:
    std::mutex theListMutex;
    std::list<int> theList;
};

现在,我相信意图很明显,而且这个例子是故意的学术性的——虽然离我的现实不远——所以让我们继续吧。然后我的应用程序处理了大量这样的对象,所有这些对象都存储在其他地方的向量中,一切都很好。当我编译时,麻烦就开始了。我正在使用 VS2012,但我相信其他编译器可能会发出类似的错误:

error C2248: 'std::mutex::mutex' : cannot access private member declared in class 'std::mutex'
1>          c:\program files\microsoft visual studio 11.0\vc\include\mutex(116) : see declaration of 'std::mutex::mutex'
1>          c:\program files\microsoft visual studio 11.0\vc\include\mutex(107) : see declaration of 'std::mutex'
1>          This diagnostic occurred in the compiler generated function 'MyApp::MyAwesomeObject ::MyAwesomeObject (const MyApp::MyAwesomeObject &)'

什么意思对我来说很清楚,在 SO 中经历了很多其他问题,所有这些基本上都说“互斥锁不能被复制”,我很好。所以到目前为止,我的策略是制作互斥体 ashared_ptr<mutex>并完成它。唯一的“缺点”是现在我在访问互斥锁时必须使用愚蠢的取消引用语法,这当然一点也不愚蠢,只是在我使用的所有其他点符号之间有点尴尬和突出这个地方。

现在,关于我的问题:使用共享指针是解决问题的正确方法吗?可能我使用了唯一的指针,因为据我所知,我没有将所有权转移给其他任何人(除非在作为对象成员的指针上调用方法实际上是所有权转移的一种形式)?还有其他方法可以解决无法复制互斥锁的事实吗?

4

5 回答 5

2

,使用 astd::shared_ptr不是处理这个问题的正确方法。

如果您希望您的对象是可复制的,则定义一个复制构造函数,将互斥锁锁定在源中,然后复制内容。Mike Spertus 为我的博客写了一篇关于此的客座文章:http ://www.justsoftwaresolutions.co.uk/threading/thread-safe-copy-constructors.html

如果您只希望您的对象是可移动的(正如乔纳森所指出的那样,这就是将其存储在向量中所需要的全部),那么您可以定义一个移动构造函数,如上所述,或者按照乔纳森的建议使用std::unique_ptr<std::mutex>.

于 2013-07-05T13:12:43.680 回答
2

所以到目前为止我的策略是使互斥锁成为shared_ptr<mutex>

等待。为什么互斥锁会在各种实例之间共享?您是否意识到这最终会保护多个theList具有相同互斥锁的互斥锁?

您不能只是将shared_ptrs 放在事情上并假装它可以解决问题。在这种情况下,它会改变语义。我希望这里的正确语义是:每个新MyAwesomeObject对象都有自己的互斥锁来保护自己的theList.

于 2013-07-05T11:04:05.427 回答
0

另一种可能性是使用 a dequeorlist代替 a vector,因为它不会对其存储的类型强加可移动/可复制的要求(假设您使用emplace_*方法构造将元素存储在容器中,并且您没有复制容器,课程)。

于 2013-07-05T14:53:04.743 回答
0

互斥策略应基于“事务范围”概念,而不是按对象/或按 this 。按那个。

现在交易范围可能是

  • A:操作单个共享数据结构,比如列表等
  • B:操作多个共享数据结构,例如多个列表、计数器等
  • C:操纵多个共享数据结构和共享外部[可能是文件描述符,或数据库连接等]资源
于 2013-07-05T12:11:04.207 回答
0

不需要 a shared_ptr,因为互斥锁的所有者永远不会超过一个。

我会使用std::unique_ptr<std::mutex>,这使您的对象只能移动,不可复制,但是可以将它们存储在vector. 这样,您可以将列表和关联互斥体的所有权从一个对象转移到另一个对象,但不能复制它们。

这意味着您MyAwesomeObject将有一个空的“移出”状态,它没有互斥体,因此不应使用它的列表。您应该添加一个成员来查询它是否处于该状态,以便用户可以判断他们是否已经获得了一个没有互斥锁的空对象:

class MyAwesomeObject {
    std::unique_ptr<std::mutex> theListMutex;
    std::list<int> theList;

public:
    bool valid() const { return (bool)theListMutex; }
};
于 2013-07-05T12:05:46.713 回答