我有一个使用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
包括内存围栏之类的东西。但是,在单线程情况下,这无关紧要,因为在应用程序执行“consume”方法时,永远不要对元素进行
push
编码,并且在循环之后警报队列应该始终为空(因为赢得了循环)直到pop
返回false
为止。我误会了吗?我的逻辑有误吗?我在
boost::lockfree::queue
中发现错误的机会很小吗? 最佳答案
该队列是无锁的,因此,如果队列已满,push
不会阻塞。lockfree::queue::push
返回一个 bool(boolean) 值,指示该元素是否已进入队列。当队列已满时,push
返回false
,因此您可能需要检查这种情况。
关于c++ - Boost的无锁队列是否有可能丢失元素?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37281969/