如何使用类似 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::deque有帮助吗?
再次编辑
首先,感谢您的想法。我对避免缄默和/或将缄默转移到对象中的解决方案不感兴趣(我不透露细节/原因(。因此,考虑到我想要一个可调整数量的互斥量的问题(其中,当没有互斥量被锁定时,保证会发生调整(,那么似乎有几种解决方案。
1我可以使用固定数量的倍数,并使用哈希函数从对象映射到倍数(如Oblivous上尉的回答(。这将导致冲突,但如果多个线程的数量远大于线程的数量,但仍然小于对象的数量,则冲突的数量应该很小。
2我可以定义一个包装类(如ComicansMS的答案(,例如
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; }
};
并使用CCD_ 4。
3我可以使用std::unique_ptr<std::mutex>
来管理单个互斥(如Matthias的回答(。这种方法的问题在于,每个互斥对象都是在堆上单独分配和取消分配的。因此,我更喜欢
4std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );
当最初分配了一定数量的多重数CCD_ 7时。如果以后发现这个数字不够,我只是
if(need_mutex > n_mutex) {
mutices.reset( new std::mutex[need_mutex] );
n_mutex = need_mutex;
}
那么我应该使用这些(1,2,4(中的哪一个呢?
vector
要求值是可移动的,以便在值增长时保持连续的值数组。你可以创建一个包含互斥的向量,但你不能做任何可能需要调整它大小的事情
其他容器没有这个要求;只要在构造过程中或通过使用emplace()
或resize()
在适当的位置构造互斥,deque
或[forward_]list
都应该工作。insert()
和push_back()
等功能将不起作用。
或者,您可以添加一个额外的间接级别并存储unique_ptr
;但你在另一个答案中的评论表明,你认为动态分配的额外成本是不可接受的。
如果你想创建一个特定的长度:
std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);
mutexes.swap(list);
您可以使用std::unique_ptr<std::mutex>
而不是std::mutex
。unique_ptr
是可移动的。
我建议使用固定的互斥池。保留一个固定的std::mutex
数组,并根据对象的地址选择要锁定的数组,就像使用哈希表一样。
std::array<std::mutex, 32> mutexes;
std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];
m.lock();
hashof
函数可以是将指针值移动几位的简单函数。这样,您只需要初始化互斥对象一次,就可以避免调整向量大小的复制。
如果效率是一个问题,我假设您只有非常小的数据结构,这些数据结构会经常更改。因此,最好使用Atomic Compare And Swap(和其他原子操作(,而不是使用互斥,特别是std::atomic_compare_exchange_strong
当我想要一个class
或struct
的std::vector
,每个都有自己的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;
};
你不需要";移动";即CCD_ 26。你只需要把它锁上;移动";其他一切。
将每个互斥对象声明为指针怎么样?
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];
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 是std :: set&lt; std :: future&gt;不可能存在
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- 使用 std::vector<boost::shared_ptr<Base_Class>> 或 boost::p tr_vector 的性能注意事项是什么<Base>
- std::map<std::set, double> AND std:<long>map< std::p air<long, long>, double>
- 如何获取std::vector<DMatch>