我有一个使用boost::lockfree::queue(来自Boost 1.57)的单线程应用程序。 (我之所以使用队列,是因为它是一个库的一部分,该库也在多线程应用程序中使用。)

似乎队列以某种方式丢失了元素。

使用队列的类的行为如下:

  • 有两个单独的函数在队列上调用push。除了队列本身提供的内容外,没有线程安全逻辑。
  • 有一个函数可以使用队列中的元素。它使用while(my_queue.pop(temp_element))循环消耗所有元素。此功能受互斥量保护,以确保所有元素归单个使用者使用。但是,如果在一行中检测到两个重复的元素(与==相比),则会跳过第二个元素。

  • 我观察到元素似乎没有在系统中一致地传播,因此使用std::atomic_uint,我创建了一些计数器来检查是否有与进入队列时相同数量的警报离开队列:
  • 两种push编码方法中的每一个都有单独的计数器。我们将其称为pushed_method1pushed_method2
  • “处理”元素和“跳过”元素有单独的计数器。我们将其称为consumedskipped。在循环中,它们将按以下方式更新(已重命名变量,并在[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::atomicboost::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/

    10-09 00:28