zoukankan      html  css  js  c++  java
  • 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.

    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.

  • 相关阅读:
    C# SqlTransaction事务,先从后主
    去除HTML标记
    GIT拉取问题
    QQ音乐API
    解决UEditor编辑器禁用时点击文本编辑器会多加一个字符问题
    UEditor编辑器增加placeholder提示
    C# List去重及优化建议
    ref和out解析
    时间标准格式转换及数值的ToString的格式化
    没有被“怼”,顺利通过华为Android三面,看看面试官都问了我什么?
  • 原文地址:https://www.cnblogs.com/sssblog/p/11330990.html
Copyright © 2011-2022 走看看