我有一个使用boost::lockfree::queue
的单线程应用程序(来自Boost 1.57)。 (我使用队列的原因是它是一个库的一部分,它也用在多线程应用程序中。)
看来队列在某种程度上会丢失元素。
使用队列的类的行为如下:
push
。除了队列本身提供的内容之外,没有线程安全逻辑。while(my_queue.pop(temp_element))
循环消耗所有元素。此功能受互斥锁保护,以确保所有元素都转到单个使用者。但是,如果连续检测到两个重复的元素(与==
相比),则跳过第二个元素。我观察到元素似乎没有一致地通过系统传播,所以使用std::atomic_uint
,我创建了一些计数器来检查相同数量的警报是否离开队列进入它:
push
方法中的每一种都有单独的计数器。我们会将这些称为pushed_method1
和pushed_method2
。“处理”元素和“跳过”元素有单独的计数器。我们会将这些称为consumed
和skipped
。在循环中,它们更新如下(重命名变量,并在[square brackets]
中使用描述性伪代码):
ElementType previous{[ initialize in invalid state ]};
while (my_queue.pop(temp_element))
{
if (! [ check if `previous` is valid ]
|| previous != temp_element)
{
[ ... log a message ]
[ ... insert the element into a vector to be returned ]
++consumed;
}
else
{
// ... log a message
++skipped;
}
previous = temp_element;
}
循环之后,我检查计数器和队列的状态并进行健全性检查:
auto postconsume_pushed_method1 = pushed_method1.load();
auto postconsume_pushed_method2 = pushed_method2.load();
auto all_consumed = my_queue.empty();
assert(
!all_consumed
|| postconsume_pushed_method1 + postconsume_pushed_method2
== consumed + skipped);
此断言通常通过 - 但单线程应用中有时会失败。 (在多线程的情况下,它有时也会失败,但我希望专注于单线程的情况来简化问题。)
在多线程的情况下,我可以想象操作正在重新排序,以便在load
检查后发生一个或多个.empty()
,但我希望不是因为我希望std::atomic
和boost::lockfree
为这类事情包含内存栅栏。
但是,在单线程的情况下,这个应该无关紧要,因为当应用程序执行“时,从不 push
使用“方法,并且警告队列应该总是在循环后为空(因为循环不会中断,直到pop
返回false
。”
我误解了什么吗?我的逻辑中有错误吗?我在boost::lockfree::queue
找到了一个错误的机会很小吗?
答案 0 :(得分:3)
队列是无锁的,因此当队列满了时push
不会阻塞。
lockfree::queue::push
返回一个布尔值,告诉该元素是否已将其放入队列中。当队列已满时,push
会返回false
,因此您可能希望检查此情况。