Boost_lockFree_SPSC_queue是否真的可变大小且数据丢失?

时间:2016-12-07 15:26:05

标签: multithreading c++11 boost blockingqueue

您好我已经计划使用boost SPSC队列。我必须有一个监听器,它总是在收到消息时监听传入消息,将消息放入队列并返回等待新消息。还有一个消费者从队列中弹出消息并对其进行处理。

由于我不希望我的监听器等待锁定写入队列,我更喜欢boost_lockfree_spsc_queue。我相信如果我在初始化队列时设置fixed_sized<false>,队列的大小会有所不同。但似乎不是。

以下是我的代码:

boost::lockfree::spsc_queue<int, boost::lockfree::fixed_sized<false>> lockFreeQ{10};

void sharedQueue::lockFreeProduce()
{

    for(int i = 0; i < 100; i++)
    {
       lockFreeQ.push(i);        
       cout<<"--"<<i<<endl;
    }

}
void sharedQueue::lockFreeConsume(){

for(int i = 0;  i <100; i++){

   /* Implement a blocking pop to the queue in order to waste cpu time  by busy waiting*/

        while(!(lockFreeQ.read_available() > 0))
           {
               //std::this_thread::yield();
                 std::this_thread::sleep_for(std::chrono::nanoseconds(10));
           }

       cout<<"   ***"<<lockFreeQ.front()<<endl;
       lockFreeQ.pop();

   }

}

void sharedQueue:: TestLockFreeQueue()
{

   std::thread t1([this]() { this->lockFreeProduce(); });
   std::thread t2([this]() { this->lockFreeConsume(); });   
   t1.join();
   t2.join();
}

输出显示数据丢失。以下是部分结果。但它错过了87号,92号。

**85
***86
***88
***90
***91
***93
***95
***96
***98

如果它是可变大小的,它应该扩展队列的大小,不应该丢失数据。它似乎覆盖了A consequence of the circular buffer is that when it is full and a subsequent write is performed, then it starts overwriting the oldest data.所解释的数据。在这种情况下,如何在不丢失数据的情况下处理这个问题?

谢谢

1 个答案:

答案 0 :(得分:0)

翻译评论以回答。

政策适用于spsc_queue的方式如下:

typedef typename mpl::if_c<runtime_sized,                                  
                           runtime_sized_ringbuffer<T, allocator>,
                           compile_time_sized_ringbuffer<T, capacity>
                          >::type ringbuffer_type;

在您的情况下,它会选择runtime_sized_ringbuffer缓冲区而不是compile_time_sized_ringbuffer

两者之间的区别是,在runtime_sized_ringbuffer的情况下,使用作为模板参数传递的allocator来分配大小数组(作为参数传递给构造函数) / em>在compile_time_sized_ringbuffer的情况下,数组在堆栈上分配。

因此,如果您的队列规模很大,则必须使用runtime_sized_ringbuffer代替compile_time_sized_ringbuffer

这是唯一的区别,在这两种情况下,基础数据结构都是circular_buffer。即使在runtime_sized_ringbuffer的情况下,一旦完成写入缓冲区中的所有位置/索引,最旧的元素将被覆盖。从下面的代码中可以看出这是非常直接的

static size_t next_index(size_t arg, size_t max_size)
{
  size_t ret = arg + 1;
  while (unlikely(ret >= max_size))
    ret -= max_size;
  return ret;
}

如果你真的需要一个无锁列表数据结构,你应该按Dmitry Vyukov

查看着名的无锁列表数据结构