0%

boost::lockfree使用介绍

boost::lockfree是boost1.53引入的无锁数据结构,包括boost::lockfree::stack、boost::lockfree::queue和boost::lockfree::spsc_queue三种,前两种用于多生产者/多消费者场景,第三个用于单生产者/单消费者场景,下面对它们的使用进行详细介绍,以boost::lockfree::stack为例,其他类似。

构造

boost::lockfree::stack源代码如下(boost 1.65):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <typename T, class A0, class A1, class A2>
#else
template <typename T, typename ...Options>
#endif
class stack
{
private:
#ifndef BOOST_DOXYGEN_INVOKED
BOOST_STATIC_ASSERT(boost::is_copy_constructible<T>::value);
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
typedef typename detail::stack_signature::bind<A0, A1, A2>::type bound_args;
#else
typedef typename detail::stack_signature::bind<Options...>::type bound_args;
#endif
static const bool has_capacity = detail::extract_capacity<bound_args>::has_capacity;
static const size_t capacity = detail::extract_capacity<bound_args>::capacity;
static const bool fixed_sized = detail::extract_fixed_sized<bound_args>::value;
static const bool node_based = !(has_capacity || fixed_sized);
static const bool compile_time_sized = has_capacity;
/* 省略 */
public:
typedef T value_type;
typedef typename implementation_defined::allocator allocator;
typedef typename implementation_defined::size_type size_type;

//! Construct stack
// @{
stack(void):
pool(node_allocator(), capacity)
{
BOOST_ASSERT(has_capacity);
initialize();
}
template <typename U>
explicit stack(typename node_allocator::template rebind<U>::other const & alloc):
pool(alloc, capacity)
{
BOOST_STATIC_ASSERT(has_capacity);
initialize();
}
explicit stack(allocator const & alloc):
pool(alloc, capacity)
{
BOOST_ASSERT(has_capacity);
initialize();
}
// @}
//! Construct stack, allocate n nodes for the freelist.
// @{
explicit stack(size_type n):
pool(node_allocator(), n)
{
BOOST_ASSERT(!has_capacity);
initialize();
}
template <typename U>
stack(size_type n, typename node_allocator::template rebind<U>::other const & alloc):
pool(alloc, n)
{
BOOST_STATIC_ASSERT(!has_capacity);
initialize();
}

boost::lockfree::stack的第一个模板参数是元素类型,后面3个参数是用来配置stack的,没有顺序要求:

  • boost::lockfree::fixed_sized:是否固定大小,默认为boost::lockfree::fixed_sized<false>,如果为true,则内部使用数组保存元素,大小不能动态增长;
  • boost::lockfree::capacity:编译时设置内部数组大小,设置了capacity意味着一定是boost::lockfree::fixed_sized<true>,和运行时指定大小是互斥的,见下面的例子;
  • boost::lockfree::allocator:设置分配器,默认boost::lockfree::allocator<std::allocator<void>>

例如:

1
2
3
4
5
6
7
8
9
10
11
//表示动态大小,初始大小为4,用完了再动态增长;此时必须在构造函数指定初始大小,否则断言失败;
boost::lockfree::stack<int> s(4);

//表示大小固定,运行时指定初始大小为4,用完后再push就会失败;此时必须在构造函数指定初始大小,否则断言失败;
boost::lockfree::stack<int, boost::lockfree::fixed_sized<true>> s1(4);

//表示大小固定,编译时指定初始大小为4,用完后再push就会失败;此时不能在构造函数指定初始大小,否则断言失败;
boost::lockfree::stack<int, boost::lockfree::capacity<4>> s2;

//和上面一样,设置了capacity,fixed_size就总是true
boost::lockfree::stack<int, boost::lockfree::fixed_size<false>, boost::lockfree::capacity<4>> s3;

成员方法

  • push:压入一个元素到容器,除了unsynchronized_,都是线程安全的。所有都是非阻塞的。
1
2
3
4
5
6
7
8
9
10
11
12
bool push(T const & v)

bool bounded_push(T const & v)

template <typename ConstIterator>
ConstIterator push(ConstIterator begin, ConstIterator end)

template <typename ConstIterator>
ConstIterator bounded_push(ConstIterator begin, ConstIterator end)

bool unsynchronized_push(T const & v)
ConstIterator unsynchronized_push(ConstIterator begin, ConstIterator end)

bounded_表示不动态增长,当初始大小用完后再push就会失败;
unsynchronized_表示非线程安全;

  • pop:从容器中弹出一个元素,除了unsynchronized_,都是线程安全的。所有都是非阻塞的。
1
2
3
4
5
6
7
8
9
bool pop(T & ret)

template <typename U>
bool pop(U & ret)

bool unsynchronized_pop(T & ret)

template <typename U>
bool unsynchronized_pop(U & ret)

unsynchronized_表示非线程安全;

  • consume_:从容器弹出1个或全部元素,并应用某个函数对象。线程安全或阻塞与否取决于函数对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <typename Functor>
bool consume_one(Functor & f)

template <typename Functor>
bool consume_one(Functor const & f)

template <typename Functor>
size_t consume_all(Functor & f)

template <typename Functor>
size_t consume_all(Functor const & f)

template <typename Functor>
size_t consume_all_atomic(Functor & f)

template <typename Functor>
size_t consume_all_atomic(Functor const & f)

template <typename Functor>
size_t consume_all_atomic_reversed(Functor & f)

template <typename Functor>
size_t consume_all_atomic_reversed(Functor const & f)

_one表示只消费1个元素;
_all表示消费所有元素;
_atomic表示消费过程是原子的,其间其他操作对其是不可见的。
_reversed表示倒序消费。

  • 其他
1
2
3
4
5
6
//预分配空闲节点数,和编译时设置capacity互斥;线程安全,可能阻塞
void reserve(size_type n)
//非线程安全
void reserve_unsafe(size_type n)
//判断是否为空
bool empty(void) const

简单示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <boost/lockfree/stack.hpp>
int main(int argc, char *argv[])
{
boost::lockfree::stack<int> s(64);
//producer
for (int i = 0; i < 1000; i++)
{
s.push(i);
}
//consumer
s.consume_all([](int i)
{
std::cout << i << std::endl;
});
return 0;
}
-------------本文结束感谢您的阅读-------------