问题描述
我有一个大的,但可能变化的数量的对象被并发写入。我想用互斥锁保护这个访问。为此,我想我使用 std :: vector< std :: mutex>
,但这不工作,因为 std :: mutex
没有复制或移动构造函数,而 std :: vector :: resize()
需要。
这个难题的推荐解决方案是什么?
编辑:
所有C ++随机存取容器需要复制或移动构造函数来重新调整大小?
首先,感谢您的帮助?
所有的想法。我不感兴趣的解决方案,避免mutices和/或将它们移动到对象(我不提供详细/原因)。所以给定的问题,我想要一个可调数量的mutices(其中保证调整,当没有mutex锁定时),然后似乎有几个解决方案。1 我可以使用固定数量的mutices,并使用哈希函数从对象映射到mutices(如Captain Oblivous的回答)。这将导致冲突,但是如果mutice的数量远大于线程数,但仍小于对象的数量,则冲突的数量应该很小。
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 []&当某个数字
n_mutex $ c $时,mutices(new std :: mutex [n_mutex]);
c>初始分配。如果后来发现这个号码不足,我只需
if(need_mutex> n_mutex){
mutices.reset new std :: mutex [need_mutex]);
n_mutex = need_mutex;那么,我应该使用这些(1,2,4)哪一个? / p>
解决方案 向量
要求值是可移动的,连续的值数组随着它的增长。你可以创建一个包含互斥体的向量,但你不能做任何可能需要调整它的大小。
其他容器没有这个要求; deque
或 [forward_] list
应该工作,只要在构建期间构建互斥体,使用 emplace()
或 resize()
。 insert()
和 push_back()
等函数将无法工作。
或者,您可以添加一个额外的间接级别并存储 unique_ptr
;但您在另一个答案中的评论表明,您认为动态分配的额外费用是不可接受的。
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.
What is the recommended solution to this conundrum?
edit:
Do all C++ random-access containers require copy or move constructors for re-sizing? Would std::deque help?
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). 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.
2 I could define a wrapper class (as in ComicSansMS's answer), e.g.
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>
.
3 I could use std::unique_ptr<std::mutex>
to manage individual mutexes (as in Matthias's answer). 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] );
when a certain number n_mutex
of mutices is allocated initially. 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?
解决方案 vector
requires that the values are movable, in order to maintain a contiguous array of values as it grows. 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()
. Functions such as insert()
and push_back()
will not work.
Alternatively, you could add an extra level of indirection and store unique_ptr
; but your comment in another answer indicates that you believe the extra cost of dynamic allocation to be unacceptable.
这篇关于如何使用像std :: vector< std :: mutex>的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!