我怎样才能使用像std :: vector <std :: mutex>这样的东西?

Wal*_*ter 25 c++ multithreading mutex vector c++11

我有一个很大但可能变化的对象,它们被同时写入.我想用互斥锁保护访问权限.为此,我认为我使用了一个std::vector<std::mutex>,但这不起作用,因为std::mutex没有复制或移动构造函数,同时std::vector::resize()需要.

这个难题的推荐解决方案是什么?

编辑:所有C++随机访问容器是否需要复制或移动构造函数来重新调整大小?std :: deque会帮助吗?

再次编辑

首先,感谢您的所有想法.我对避免突变和/或将它们移动到对象中的解决方案不感兴趣(我不提供细节/原因).因此,考虑到我想要一个可调数量的mutices(在没有锁定互斥锁时保证调整的情况)的问题,那么似乎有几种解决方案.

1我可以使用固定数量的mutices并使用哈希函数从对象映射到mutices(如Oblivous上尉的答案).这将导致冲突,但如果mutices的数量远大于线程数,但仍然小于对象数,则冲突的数量应该很小.

2我可以定义一个包装类(如在ComicSansMS的答案中),例如

struct mutex_wrapper : std::mutex
{
  mutex_wrapper() = default;
  mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {}
  bool operator==(mutex_wrapper const&other) noexcept { return this==&other; }
};
Run Code Online (Sandbox Code Playgroud)

并使用一个std::vector<mutex_wrapper>.

3我可以std::unique_ptr<std::mutex>用来管理单个互斥体(如Matthias的答案).这种方法的问题是每个互斥锁在堆上单独分配和解除分配.因此,我更喜欢

4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );

n_mutex最初分配一定数量的mutices时.如果以后发现这个数字不够,我只是

if(need_mutex > n_mutex) {
  mutices.reset( new std::mutex[need_mutex] );
  n_mutex = need_mutex;
}
Run Code Online (Sandbox Code Playgroud)

那么我应该使用这些(1,2,4)中的哪一个?

Mik*_*our 13

vector要求值是可移动的,以便在增长时保持连续的值数组.您可以创建包含互斥锁的向量,但是您无法执行任何可能需要调整其大小的操作.

其他容器没有这个要求; 只要您在构造期间或使用或构建互斥锁,就可以使用deque或者[forward_]list应该工作.诸如和不起作用的功能.emplace()resize()insert()push_back()

或者,您可以添加额外级别的间接和存储unique_ptr; 但是您在另一个答案中的评论表明您认为动态分配的额外成本是不可接受的.

  • @Walter:如果你想调整向量的大小,你就不能使用它;将其包装在“unique_ptr”中不会有任何区别。如果你有一个“固定”的数字,那么一个适当构造的向量应该可以工作;但你说“可能变化”,这排除了使用“向量”。 (2认同)

Mat*_*ard 12

你可以用std::unique_ptr<std::mutex>而不是std::mutex. unique_ptrs是可移动的.

  • @Walter:这是一个非常明智的建议,如果额外的内存占用和额外的间接级别的成本是可以接受的. (5认同)
  • 并在堆上单独创建每个互斥锁?你在开玩笑吗? (2认同)
  • @Walter:为什么不创建一个保持互斥锁与其对象关联的类?然后编写自定义的复制和移动构造函数以及赋值运算符,它们允许您的类在容器中使用.保持裸露的互斥体看起来有点傻. (2认同)

小智 9

如果要创建一定长度:

std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);

mutexes.swap(list);
Run Code Online (Sandbox Code Playgroud)

  • 这个答案证实了 `vector` 不需要可移动构造的项目。这取决于你对 `vector` 做什么。您可以以一种方式增加 `vector&lt;mutex&gt;`(* 仅一种方式,您的 `swap` 技巧),但您可以轻松缩小这样的向量,并且您可以(如您的答案)确保它具有正确的大小开始。 (3认同)
  • 在弄乱它之后,我现在明白为什么了;如果您使用 .swap() 来增长向量,则所有元素都是新的。 (3认同)

Cap*_*ous 6

我建议使用固定的互斥池。保留一个固定数组,std::mutex并根据对象的地址选择要锁定的数组,就像使用哈希表一样。

std::array<std::mutex, 32> mutexes;

std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];

m.lock();
Run Code Online (Sandbox Code Playgroud)

hashof函数可以是简单的函数,将指针值移动几个位。这样,您只需初始化互斥体一次,就可以避免调整向量大小的副本。