问题描述
来源有以下评论:
// Return the number of items in the queue; thread unsafe
std::ptrdiff_t size() const {
return my_queue_representation->size();
}
但后来我查看了内部实现,这一切似乎都是线程安全的(操作是 std::atomic
的负载,然后是一些减法)。
std::ptrdiff_t size() const {
__TBB_ASSERT(sizeof(std::ptrdiff_t) <= sizeof(size_type),NULL);
std::ptrdiff_t hc = head_counter.load(std::memory_order_acquire);
std::ptrdiff_t tc = tail_counter.load(std::memory_order_relaxed);
std::ptrdiff_t nie = n_invalid_entries.load(std::memory_order_relaxed);
return tc - hc - nie;
}
解决方法
它是线程安全的,因为 C++ 标准对行为进行了明确定义,即没有标准中定义的竞争条件。它不是线程安全的,因为结果是队列的原子快照,即不是顺序一致的实现。
允许负尺寸是一个深思熟虑的设计决定。 N 的负大小表示有 N 个待处理的弹出。老版本的 TBB 有这样的评论:
//! Integral type for representing size of the queue.
/** Note that the size_type is a signed integral type.
This is because the size can be negative if there are pending pops without corresponding pushes. */
typedef std::ptrdiff_t size_type;
最新版本似乎缺少评论。 (我是 TBB 的原始架构师,但不再为 Intel 工作,所以我不能代表当前版本的意图。)
队列静止时返回值准确,非静止时可能不准确。在实践中,实现 size()
返回原子快照不会增加太多价值,因为如果队列处于活动状态,返回值可能会立即变得不准确。这就是为什么有 try_push
和 try_pop
之类的操作,而不是像在常规 STL 中那样让用户检查队列,然后将其作为单独的操作进行操作。