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

时间:2013-05-09 15:37:35

标签: c++ multithreading c++11 vector mutex

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

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

修改: 是否所有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; }
};

并使用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;
}

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

6 个答案:

答案 0 :(得分:11)

您可以使用std::unique_ptr<std::mutex>代替std::mutexunique_ptr可以移动。

答案 1 :(得分:11)

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

其他容器没有这个要求;只要您在构建期间或使用deque[forward_]list构建互斥锁,emplace()resize()就可以正常工作。 insert()push_back()等功能无效。

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

答案 2 :(得分:7)

如果您想创建一定长度:

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

mutexes.swap(list);

答案 3 :(得分:3)

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

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

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

m.lock();

hashof函数可能很简单,可以将指针值移动几位。这样,您只需初始化互斥锁一次就可以避免复制矢量大小的副本。

答案 4 :(得分:2)

如果效率是一个问题,我假设您只有非常小的数据结构,这些结构经常发生变化。那么使用原子比较和交换(以及其他原子操作)而不是使用互斥锁可能更好,特别是std::atomic_compare_exchange_strong

答案 5 :(得分:0)

如何将每个互斥体声明为指针?

std::vector<std::mutex *> my_mutexes(10)
//Initialize mutexes
for(int i=0;i<10;++i) my_mutexes[i] = new std::mutex();

//Release mutexes
for(int i=0;i<10;++i) delete my_mutexes[i];