boost lockfree

Boost.Lockfree provides thread-safe and lock-free containers. Containers from this library can be accessed from multiple threads without having to synchronize access.

1. boost::lockfree::spsc_queue

#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>

boost::lockfree::spsc_queue<int> q(100);
int sum = 0;

void produce()
{
  for (int i = 1; i <= 100; ++i)
    q.push(i);
}

void consume()
{
  int i;
  while (q.pop(i))
    sum += i;
}

int main()
{
  std::thread t1(produce);
  std::thread t2(consume);
  t1.join();
  t2.join();
  consume();
  std::cout << sum << std::endl;
  return 0;
}

boost::lockfree::spsc_queue is optimized for use cases where exactly one thread writes to the queue and exactly one thread reads from the queue. The abbreviation spsc in the class name stands for single producer/single consumer.

The first thread, which executes the function produce(), adds the numbers 1 to 100 to the container. The second thread, which executes consume(), reads the numbers from the container and adds them up in sum. Because the container boost::lockfree::spsc_queue explicityly supports concurrent access from two threads, it isn't necessary to synchronize the threads.

The size of the queue is passed to the constructor. boost::lockfree:;spsc_queue is implemented with a circular buffer. If a value can't be added because the queue is full, push() returns false.

2. boost::lockfree::spsc_queue with boost::lockfree::capacity

#include <boost/lockfree/spsc_queue.hpp>
#include <boost/lockfree/policies.hpp>
#include <thread>
#include <iostream>

using namespace boost::lockfree;

spsc_queue<int, capacity<100>> q;
int sum = 0;

void produce()
{
  for (int i = 1; i <= 100; ++i)
    q.push(i);
}

void consume()
{
  while (q.consume_one([](int i){ sum += i; }))
    ;
}

int main()
{
  std::thread t1{produce};
  std::thread t2{consume};
  t1.join();
  t2.join();
  q.consume_all([](int i){ sum += i; });
  std::cout << sum << std::endl;
  return 0;
}

The capacity cannot be set at run time.

consume_one() reads a number just like pop(), but the number isn't returned through a reference to the caller. It is passed as the sole parameter to the lambda function. When the threads terminate, main() calls the member function consume_all(), instead of consume(). consume_all() works like consume_one() but makes sure that the queue is empty after the call. consume_all() calls the lambda function as long as there are elements in the queue.

3. boost::lockfree::queue with variable container size

#include <boost/lockfree/queue.hpp>
#include <thread>
#include <atomic>
#include <iostream>

boost::lockfree::queue<int> q{100};
std::atomic<int> sum{0};

void produce()
{
  for (int i = 1; i <= 10000; ++i)
    q.push(i);
}

void consume()
{
  int i;
  while (q.pop(i))
    sum += i;
}

int main()
{
  std::thread t1{produce};
  std::thread t2{consume};
  std::thread t3{consume};
  t1.join();
  t2.join();
  t3.join();
  consume();
  std::cout << sum << std::endl;
  return 0;
}

Because more that one thread reads from the queue, the class boost::lockfree::spsc_queue must not be used.

By default, boost::lockfree_queue is not implemented with a circular buffer. If more items are added to the queue than the capacity is set to, it is atuomatically increased. boost::lockfree::queue dynamically allocates additional memory if the initial size isn't sufficient.

扫描二维码关注公众号,回复: 6997131 查看本文章

4. boost::lockfree::queue with constant container size

#include <boost/lockfree/queue.hpp>
#include <thread>
#include <atomic>
#include <iostream>

using namespace boost::lockfree;

queue<int, fixed_sized<true>> q{10000};
std::atomic<int> sum{0};

void produce()
{
  for (int i = 1; i <= 10000; ++i)
    q.push(i);
}

void consume()
{
  int i;
  while (q.pop(i))
    sum += i;
}

int main()
{
  std::thread t1{produce};
  std::thread t2{consume};
  std::thread t3{consume};
  t1.join();
  t2.join();
  t3.join();
  consume();
  std::cout << sum << std::endl;
  return 0;
}

The queue's capacity is constant because boost::lockfree::fixed_sized is passed as a template parameter. The capacity is passed as a parameter to the constructor an can be updated at any time using reserve().

the queue has a capacity of 10,000 elements. Because consume() inserts 10,000 numbers into the queue, the upper limit isn’t exceeded. If it were exceeded, push() would return false.

猜你喜欢

转载自www.cnblogs.com/sssblog/p/11330990.html