[英]How can I use something like std::vector<std::mutex>?
I have a large, but potentially varying, number of objects which are concurrently written into.我有大量但可能不同的对象同时写入。 I want to protect that access with mutexes.
我想用互斥锁保护该访问。 To that end, I thought I use a
std::vector<std::mutex>
, but this doesn't work, since std::mutex
has no copy or move constructor, while std::vector::resize()
requires that.为此,我想我使用
std::vector<std::mutex>
,但这不起作用,因为std::mutex
没有复制或移动构造函数,而std::vector::resize()
需要那。
What is the recommended solution to this conundrum?这个难题的推荐解决方案是什么?
edit : Do all C++ random-access containers require copy or move constructors for re-sizing?编辑:是否所有 C++ 随机访问容器都需要复制或移动构造函数来重新调整大小? Would std::deque help?
std::deque 会有帮助吗?
edit again再次编辑
First, thanks for all your thoughts.首先,感谢您的所有想法。 I'm not interested in solutions that avoid mutices and/or move them into the objects (I refrain from giving details/reasons).
我对避免静音和/或将它们移动到对象中的解决方案不感兴趣(我不提供细节/原因)。 So given the problem that I want a adjustable number of mutices (where the adjustment is guaranteed to occur when no mutex is locked), then there appear to be several solutions.
因此,考虑到我想要可调数量的互斥锁(在没有互斥锁锁定时保证进行调整)的问题,那么似乎有几种解决方案。
1 I could use a fixed number of mutices and use a hash-function to map from objects to mutices (as in Captain Oblivous's answer). 1我可以使用固定数量的 mutic,并使用哈希函数从对象映射到 mutic(如 Oblivous 上尉的回答)。 This will result in collisions, but the number of collisions should be small if the number of mutices is much larger than the number of threads, but still smaller than the number of objects.
这会导致冲突,但是如果mutices的数量远大于线程的数量,但仍然小于对象的数量,那么冲突的数量应该很小。
2 I could define a wrapper class (as in ComicSansMS's answer), eg 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; }
};
and use a std::vector<mutex_wrapper>
.并使用
std::vector<mutex_wrapper>
。
3 I could use std::unique_ptr<std::mutex>
to manage individual mutexes (as in Matthias's answer). 3我可以使用
std::unique_ptr<std::mutex>
来管理单个互斥锁(如 Matthias 的回答)。 The problem with this approach is that each mutex is individually allocated and de-allocated on the heap.这种方法的问题在于,每个互斥体都是在堆上单独分配和取消分配的。 Therefore, I prefer
因此,我更喜欢
4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );
4
std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );
when a certain number n_mutex
of mutices is allocated initially.当最初分配一定数量的
n_mutex
互斥体时。 Should this number later be found insufficient, I simply如果以后发现这个数字不够,我只是
if(need_mutex > n_mutex) {
mutices.reset( new std::mutex[need_mutex] );
n_mutex = need_mutex;
}
So which of these (1,2,4) should I use?那么我应该使用这些 (1,2,4) 中的哪一个?
vector
requires that the values are movable, in order to maintain a contiguous array of values as it grows. vector
要求值是可移动的,以便在增长时保持连续的值数组。 You could create a vector containing mutexes, but you couldn't do anything that might need to resize it.您可以创建一个包含互斥体的向量,但您无法执行任何可能需要调整其大小的操作。
Other containers don't have that requirement;其他容器没有这个要求; either
deque
or [forward_]list
should work, as long as you construct the mutexes in place either during construction, or by using emplace()
or resize()
.只要在构造过程中或使用
emplace()
或resize()
构造互斥锁, deque
或[forward_]list
都应该工作。 Functions such as insert()
and push_back()
will not work.诸如
insert()
和push_back()
函数将不起作用。
Alternatively, you could add an extra level of indirection and store unique_ptr
;或者,您可以添加额外的间接级别并存储
unique_ptr
; but your comment in another answer indicates that you believe the extra cost of dynamic allocation to be unacceptable.但是您在另一个答案中的评论表明您认为动态分配的额外成本是不可接受的。
If you want to create a certain length:如果要创建某个长度:
std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);
mutexes.swap(list);
You could use std::unique_ptr<std::mutex>
instead of std::mutex
.您可以使用
std::unique_ptr<std::mutex>
而不是std::mutex
。 unique_ptr
s are movable. unique_ptr
是可移动的。
I suggest using a fixed mutex pool.我建议使用固定的互斥池。 Keep a fixed array of
std::mutex
and select which one to lock based on the address of the object like you might do with a hash table.保留一个固定的
std::mutex
数组,并根据对象的地址选择要锁定的数组,就像使用哈希表一样。
std::array<std::mutex, 32> mutexes;
std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];
m.lock();
The hashof
function could be something simple that shifts the pointer value over a few bits. hashof
函数可能很简单,将指针值移动几位。 This way you only have to initialize the mutexes once and you avoid the copy of resizing the vector.这样您只需初始化一次互斥体,就可以避免调整向量大小的副本。
If efficiency is such a problem, I assume that you have only very small data structures which are changed very often.如果效率是一个问题,我假设您只有非常小的数据结构,并且经常更改。 It is then probably better to use Atomic Compare And Swap (and other atomic operations) instead of using mutexes, specifically
std::atomic_compare_exchange_strong
那么最好使用原子比较和交换(和其他原子操作)而不是使用互斥锁,特别是
std::atomic_compare_exchange_strong
I'll sometimes use a solution along the lines of your 2nd option when I want a std::vector
of class
es or struct
s that each have their own std::mutex
.当我想要一个
std::vector
class
es 或struct
s 时,我有时会使用你的第二个选项的解决方案,每个类都有自己的std::mutex
。 Of course, it is a bit tedious as I write my own copy/move/assignment operators.当然,当我编写自己的复制/移动/赋值运算符时,这有点乏味。
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;
};
You don't need to "move" the std::mutex
.您不需要“移动”
std::mutex
。 You just need to hold a lock on it while you "move" everything else.您只需要在“移动”其他所有东西时锁定它即可。
How about declaring each mutex as a pointer?如何将每个互斥体声明为指针?
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];
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.