对 std::queue 的弹出和推送操作使用单独的互斥体而不是一个
Using separate mutexs for pop and push operatin of std::queue instead of one
假设有一个生产者和多个消费者,他们使用一个std::queue
,为了保护std::queue
中的数据,访问这个std::queue
时必须使用互斥量。
但是使用两个单独的锁呢?一份用于 pop
一份用于 push
?我认为使用两个单独的锁可能会更快。
我看了STL源代码。 std::queue
默认由 std::deque
实现。 pop_front()
和 push_back()
使用两个独立的迭代器访问数据,一个用于第一个元素,一个用于最后一个元素。
void push_front(const value_type& __x){
if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first){
this->_M_impl.construct(this->_M_impl._M_start._M_ur - 1, __x);
} else {
_M_push_front_aux(__x);
}
}
void push_back(){
if (this->_M_impl._M_finish._M_cur != this->_M_impl._M_finish._M_first){
this->_M_impl.construct(this->_M_impl._M_finish._M_ur - 1, __x);
} else {
_M_pop_back_aux();
}
}
因此,当一个线程 pop
进入队列时,另一个线程插入并尝试 push_back
。因为这两个操作使用不同的迭代器指向deque
的两个不同的端点,所以看起来这两个操作都可以吗?
pop_front
和 push_back
可能在内部访问不同的迭代器,但这就是抽象的全部意义:你不能确定这一点,而且不允许依赖它。
而且,正如评论中已经指出的那样,还有 size
,这是因为 C++11 需要在 O(1)
中执行。为了满足这个要求,push_back
和 pop_front
都需要改变一些内部存储,如果大小,这肯定是你有竞争条件的地方。
然后想想当你的队列变空时会发生什么......
简而言之:不要那样做。要在并发设置中使用 std::queue
,您需要一个互斥体来保护它。
作为替代方案,您应该研究无锁数据结构。
假设有一个生产者和多个消费者,他们使用一个std::queue
,为了保护std::queue
中的数据,访问这个std::queue
时必须使用互斥量。
但是使用两个单独的锁呢?一份用于 pop
一份用于 push
?我认为使用两个单独的锁可能会更快。
我看了STL源代码。 std::queue
默认由 std::deque
实现。 pop_front()
和 push_back()
使用两个独立的迭代器访问数据,一个用于第一个元素,一个用于最后一个元素。
void push_front(const value_type& __x){
if (this->_M_impl._M_start._M_cur != this->_M_impl._M_start._M_first){
this->_M_impl.construct(this->_M_impl._M_start._M_ur - 1, __x);
} else {
_M_push_front_aux(__x);
}
}
void push_back(){
if (this->_M_impl._M_finish._M_cur != this->_M_impl._M_finish._M_first){
this->_M_impl.construct(this->_M_impl._M_finish._M_ur - 1, __x);
} else {
_M_pop_back_aux();
}
}
因此,当一个线程 pop
进入队列时,另一个线程插入并尝试 push_back
。因为这两个操作使用不同的迭代器指向deque
的两个不同的端点,所以看起来这两个操作都可以吗?
pop_front
和 push_back
可能在内部访问不同的迭代器,但这就是抽象的全部意义:你不能确定这一点,而且不允许依赖它。
而且,正如评论中已经指出的那样,还有 size
,这是因为 C++11 需要在 O(1)
中执行。为了满足这个要求,push_back
和 pop_front
都需要改变一些内部存储,如果大小,这肯定是你有竞争条件的地方。
然后想想当你的队列变空时会发生什么......
简而言之:不要那样做。要在并发设置中使用 std::queue
,您需要一个互斥体来保护它。
作为替代方案,您应该研究无锁数据结构。