提问人:Walter 提问时间:5/9/2013 最后编辑:Mateusz PiotrowskiWalter 更新时间:10/23/2021 访问量:36224
如何使用 std::vector<std::mutex> 之类的东西?
How can I use something like std::vector<std::mutex>?
问:
我有大量但可能变化的对象并发写入。我想用互斥锁来保护这种访问。为此,我以为我使用了 ,但这不起作用,因为没有复制或移动构造函数,而需要它。std::vector<std::mutex>
std::mutex
std::vector::resize()
这个难题的推荐解决方案是什么?
编辑: 是否所有 C++ 随机访问容器都需要复制或移动构造函数来调整大小?std::d eque 会有帮助吗?
再次编辑
首先,感谢您的所有想法。我对避免混淆和/或将它们移动到对象中的解决方案不感兴趣(我不给出细节/原因)。因此,鉴于我想要可调整的互斥锁数量的问题(当没有互斥锁时保证进行调整),那么似乎有几种解决方案。
1 我可以使用固定数量的互斥体,并使用哈希函数从对象映射到互斥体(如 Captain Oblivous 的回答)。这将导致冲突,但如果互斥数远大于线程数,但仍小于对象数,则冲突数应该很小。
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 我可以用来管理单个互斥锁(如 Matthias 的回答)。这种方法的问题在于,每个互斥锁都是在堆上单独分配和取消分配的。因此,我更喜欢std::unique_ptr<std::mutex>
4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );
当最初分配一定数量的互补时。如果后来发现这个数字不够,我只是n_mutex
if(need_mutex > n_mutex) {
mutices.reset( new std::mutex[need_mutex] );
n_mutex = need_mutex;
}
那么我应该使用其中的哪一个(1,2,4)呢?
答:
您可以使用代替 .s 是可移动的。std::unique_ptr<std::mutex>
std::mutex
unique_ptr
评论
vector
要求值是可移动的,以便在值增长时保持连续的值数组。您可以创建一个包含互斥锁的向量,但您不能执行任何可能需要调整其大小的操作。
其他容器没有该要求;要么 or 应该工作,只要您在构造过程中就地构造互斥锁,或者使用 或 .诸如 和 之类的函数将不起作用。deque
[forward_]list
emplace()
resize()
insert()
push_back()
或者,您可以添加额外的间接和存储级别;但是您在另一个答案中的评论表明您认为动态分配的额外成本是不可接受的。unique_ptr
评论
std::unique_ptr<std::vector<std::mutex>>
std::deque
emplace()
emplace()
push_back()
unique_ptr
vector
我建议使用固定互斥池。保留一个固定的数组,并根据对象的地址选择要锁定的数组,就像使用哈希表一样。std::mutex
std::array<std::mutex, 32> mutexes;
std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];
m.lock();
该函数可以是一些简单的函数,它将指针值移动几位。这样,您只需初始化一次互斥锁,即可避免调整向量大小的副本。hashof
评论
如果效率是一个问题,我假设你只有非常小的数据结构,这些结构经常变化。因此,最好使用原子比较和交换(以及其他原子操作)而不是使用互斥锁,特别是std::atomic_compare_exchange_strong
如果要创建特定长度:
std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);
mutexes.swap(list);
评论
vector
vector
vector<mutex>
swap
将每个互斥锁声明为指针怎么样?
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];
当我想要一个 es 或 s 时,我有时会按照您的第二个选项使用解决方案,每个选项都有自己的 .当然,这有点乏味,因为我编写了自己的复制/移动/赋值运算符。std::vector
class
struct
std::mutex
struct MyStruct {
MyStruct() : value1(0), value2(0) {}
MyStruct(const MyStruct& other) {
std::lock_guard<std::mutex> l(other.mutex);
value1 = other.value1;
value2 = other.value2;
}
MyStruct(MyStruct&& other) {
std::lock_guard<std::mutex> l(other.mutex);
value1 = std::exchange(other.value1, 0);
value2 = std::exchange(other.value2, 0);
}
MyStruct& operator=(MyStruct&& other) {
std::lock_guard<std::mutex> l1(this->mutex), l2(other.mutex);
std::swap(value1, other.value1);
std::swap(value2, other.value2);
return *this;
}
MyStruct& operator=(const MyStruct& other) {
// you get the idea
}
int value1;
double value2;
mutable std::mutex mutex;
};
您不需要“移动”.你只需要在“移动”其他所有东西时按住它。std::mutex
评论
vector
只需要对象是可移动的,并且它们需要是不可投掷移动的。resize
std::mutex
collection<T>
collection<mutex>
collection<std::atomic<T>>