boost1.53中的lock-free

  原始网站:http://www.boost.org/doc/libs/1_53_0/doc/html/lockfree.html

     前言
  Boost1.53版本中新增加了lock-free库,终于有这么一款官方的lock-free结构出来了。以前在做高性能服务器处理的时候自己费了不少精力去网上搜索代码测试,不仅浪费精力而且可靠性还不敢保证。当然在项目中我使用最多的还是one-one的circle-buffer的方式,其实也就是boost::lockfree::spsc_queue,lock-free结构减少了大量的系统调用,因此特定场合下提升的性能还是非常明显的。总而言之,Boost的lock-free库还是比较值得期待和学习的。

  Non-blocking数据结构不再依赖于locks和mutexes去保证线程的安全。同步的操作完全在user-space完成,不需要直接和操作系统交互。不再依赖于guards,non-blocking数据结构需要atomic operations,尤其是CPU执行中不被中断。并不是所有的硬件支持相同系列的 atomic instructions,硬件不支持的将会使用gurard来进行模拟,当然这已经失去了lock-free的优势。

     影响lock-free的三种情况:

      Atomic Operations: 硬件提供atomic操作,这时候将会用spinlocks进行模拟,则会导致操作被block。
     
Memory Allocations:操作系统的内存分配不是lock-free的。因此没有办法去实现真正的dynamically-sized的数据结构。boost.lockfree使用memory pool去分配内部的nodes。如果memory pool耗尽,则新节点的内存需要向操作系统进行索取导致内存分配。但是对于boost.lockfree可以采用special call访问失败的方式来避免内存分配。见后续lock-free内存相关设置
  
Exception Handling:C++ exception处理没有任何保证其real-time处理的行为。因此我们不鼓励在excetion的处理中使用lock-free代码。

     Boost.lockfree实现了三种数据结构
     boost::lockfree::queue: a lock-free multi-produced/multi-consumer queue
     boost::lockfree::stack: a lock-free multi-produced/multi-consumer stack
     boost::lockfree::spsc_queue: a wait-free single-producer/single-consumer queue (commonly known as ringbuffer)
    
    lock-free内存相关设置:
  • boost::lockfree::fixed_sized, defaults to boost::lockfree::fixed_sized<false> Can be used to completely disable dynamic memory allocations during push in order to ensure lockfree behavior. If the data structure is configured as fixed-sized, the internal nodes are stored inside an array and they are addressed by array indexing. This limits the possible size of the queue to the number of elements that can be addressed by the index type (usually 2**16-2), but on platforms that lack double-width compare-and-exchange instructions, this is the best way to achieve lock-freedom.

  • boost::lockfree::capacity, optional If this template argument is passed to the options, the size of the queue is set at compile-time. It this option implies fixed_sized<true>

    
     Example
  
 1 #include <boost/thread/thread.hpp>
 2 #include <boost/lockfree/queue.hpp>
 3 #include <iostream>
 4 
 5 #include <boost/atomic.hpp>
 6 
 7 boost::atomic_int producer_count(0);
 8 boost::atomic_int consumer_count(0);
 9 
10 boost::lockfree::queue<int> queue(128);
11 
12 const int iterations = 10000000;
13 const int producer_thread_count = 4;
14 const int consumer_thread_count = 4;
15 
16 void producer(void)
17 {
18     for (int i = 0; i != iterations; ++i) {
19         int value = ++producer_count;
20         while (!queue.push(value))
21             ;
22     }
23 }
24 
25 boost::atomic<bool> done (false);
26 void consumer(void)
27 {
28     int value;
29     while (!done) {
30         while (queue.pop(value))
31             ++consumer_count;
32     }
33 
34     while (queue.pop(value))
35         ++consumer_count;
36 }
37 
38 int main(int argc, char* argv[])
39 {
40     using namespace std;
41     cout << "boost::lockfree::queue is ";
42     if (!queue.is_lock_free())
43         cout << "not ";
44     cout << "lockfree" << endl;
45 
46     boost::thread_group producer_threads, consumer_threads;
47 
48     for (int i = 0; i != producer_thread_count; ++i)
49         producer_threads.create_thread(producer);
50 
51     for (int i = 0; i != consumer_thread_count; ++i)
52         consumer_threads.create_thread(consumer);
53 
54     producer_threads.join_all();
55     done = true;
56 
57     consumer_threads.join_all();
58 
59     cout << "produced " << producer_count << " objects." << endl;
60     cout << "consumed " << consumer_count << " objects." << endl;
61 }
 1 #include <boost/thread/thread.hpp>
 2 #include <boost/lockfree/stack.hpp>
 3 #include <iostream>
 4 
 5 #include <boost/atomic.hpp>
 6 
 7 boost::atomic_int producer_count(0);
 8 boost::atomic_int consumer_count(0);
 9 
10 boost::lockfree::stack<int> stack(128);
11 
12 const int iterations = 1000000;
13 const int producer_thread_count = 4;
14 const int consumer_thread_count = 4;
15 
16 void producer(void)
17 {
18     for (int i = 0; i != iterations; ++i) {
19         int value = ++producer_count;
20         while (!stack.push(value))
21             ;
22     }
23 }
24 
25 boost::atomic<bool> done (false);
26 
27 void consumer(void)
28 {
29     int value;
30     while (!done) {
31         while (stack.pop(value))
32             ++consumer_count;
33     }
34 
35     while (stack.pop(value))
36         ++consumer_count;
37 }
38 
39 int main(int argc, char* argv[])
40 {
41     using namespace std;
42     cout << "boost::lockfree::stack is ";
43     if (!stack.is_lock_free())
44         cout << "not ";
45     cout << "lockfree" << endl;
46 
47     boost::thread_group producer_threads, consumer_threads;
48 
49     for (int i = 0; i != producer_thread_count; ++i)
50         producer_threads.create_thread(producer);
51 
52     for (int i = 0; i != consumer_thread_count; ++i)
53         consumer_threads.create_thread(consumer);
54 
55     producer_threads.join_all();
56     done = true;
57 
58     consumer_threads.join_all();
59 
60     cout << "produced " << producer_count << " objects." << endl;
61     cout << "consumed " << consumer_count << " objects." << endl;
62 }
 1 #include <boost/thread/thread.hpp>#include <boost/lockfree/spsc_queue.hpp>
 2 #include <iostream>#include <boost/atomic.hpp>int producer_count = 0;
 3 boost::atomic_int consumer_count (0);
 4 boost::lockfree::spsc_queue<int, boost::lockfree::capacity<1024> > spsc_queue;
 5 const int iterations = 10000000;void producer(void){
 6     for (int i = 0; i != iterations; ++i) {        int value = ++producer_count;
 7         while (!spsc_queue.push(value))            ;    }}
 8 boost::atomic<bool> done (false);void consumer(void){    int value;
 9     while (!done) {        while (spsc_queue.pop(value))
10             ++consumer_count;    }    while (spsc_queue.pop(value))
11         ++consumer_count;}int main(int argc, char* argv[]){
12     using namespace std;    cout << "boost::lockfree::queue is ";
13     if (!spsc_queue.is_lock_free())        cout << "not ";
14     cout << "lockfree" << endl;    boost::thread producer_thread(producer);
15     boost::thread consumer_thread(consumer);    producer_thread.join();
16     done = true;    consumer_thread.join();
17     cout << "produced " << producer_count << " objects." << endl;
18     cout << "consumed " << consumer_count << " objects." << endl;}

 

 

posted on 2013-03-31 12:32  深入浅出eBPF  阅读(3435)  评论(0编辑  收藏  举报

导航