boost::lockfree::queue
// In header: <boost/lockfree/queue.hpp> template<typename T, typename... Options> class queue { public: // types typedef T value_type; typedef implementation_defined::allocator allocator; typedef implementation_defined::size_type size_type; // public member functions bool is_lock_free(void) const; queue(void); template<typename U, typename Enabler = std::enable_if< has_capacity > > explicit queue(typename boost::allocator_rebind< node_allocator, U >::type const &); template<typename Enabler = std::enable_if< has_capacity > > explicit queue(allocator const &); template<typename Enabler = std::enable_if< !has_capacity > > explicit queue(size_type); template<typename U, typename Enabler = std::enable_if< !has_capacity > > queue(size_type, typename boost::allocator_rebind< node_allocator, U >::type const &); template<typename Enabler = std::enable_if< !has_capacity > > queue(size_type, allocator const &); queue(const queue &) = delete; queue & operator=(const queue &) = delete; queue(queue &&) = delete; queue & operator=(queue &&) = delete; void reserve(size_type); void reserve_unsafe(size_type); ~queue(void); bool empty(void) const; bool push(const T &); bool push(T &&); bool bounded_push(const T &); bool bounded_push(T &&); bool unsynchronized_push(T &&); bool pop(T &); template<typename U> bool pop(U &); std::optional< T > pop(uses_optional_t); template<typename U> std::optional< U > pop(uses_optional_t); bool unsynchronized_pop(T &); template<typename U> bool unsynchronized_pop(U &); template<typename Functor> bool consume_one(Functor &&); template<typename Functor> size_t consume_all(Functor &&); };
queue 类提供了一个多写入器/多读取器的队列,入队和出队是无锁的,构造/析构必须同步。它使用空闲链表进行内存管理,释放的节点被推入空闲链表,直到队列被销毁才返回给操作系统。
策略
boost::lockfree::fixed_sized,默认为 boost::lockfree::fixed_sized<false>
可用于完全禁用入队时的动态内存分配,以确保无锁行为。
如果数据结构配置为固定大小,则内部节点存储在一个数组中,并通过数组索引进行寻址。这会将队列的大小限制在索引类型可以寻址的元素数量(通常为 2**16-2)以内,但在缺少双宽度比较和交换指令的平台上,这是实现无锁的最佳方式。
boost::lockfree::capacity,可选
如果将此模板参数传递给选项,则队列的大小将在编译时确定。
此选项隐含 fixed_sized<true>
boost::lockfree::allocator,默认为 boost::lockfree::allocator<std::allocator<void>>
指定用于内部空闲链表的分配器
要求
T 必须有拷贝构造函数
T 必须有平凡的赋值运算符
T 必须有平凡的析构函数
bool is_lock_free(void) const;
![]() |
警告 |
---|---|
它仅检查队列头尾节点和空闲链表是否可以无锁修改。在大多数平台上,如果为 true,则整个实现都是无锁的。使用 C++0x 风格的原子操作,无法提供完全准确的实现,因为需要测试每个内部节点,如果还需要从操作系统分配新节点,这是不可能的。 |
返回 |
如果实现是无锁的,则为 true。 |
queue(void);
构造一个固定大小的队列
要求 |
必须指定 capacity<> 参数 |
template<typename U, typename Enabler = std::enable_if< has_capacity > > explicit queue(typename boost::allocator_rebind< node_allocator, U >::type const & alloc);
使用自定义分配器构造一个固定大小的队列
要求 |
必须指定 capacity<> 参数 |
template<typename Enabler = std::enable_if< has_capacity > > explicit queue(allocator const & alloc);
使用自定义分配器构造一个固定大小的队列
要求 |
必须指定 capacity<> 参数 |
template<typename Enabler = std::enable_if< !has_capacity > > explicit queue(size_type n);
构造一个可变大小的队列
为空闲链表初始分配 n 个节点
要求 |
不能指定 capacity<> 参数 |
template<typename U, typename Enabler = std::enable_if< !has_capacity > > queue(size_type n, typename boost::allocator_rebind< node_allocator, U >::type const & alloc);
使用自定义分配器构造一个可变大小的队列
为空闲链表初始分配 n 个节点
要求 |
不能指定 capacity<> 参数 |
template<typename Enabler = std::enable_if< !has_capacity > > queue(size_type n, allocator const & alloc);
使用自定义分配器构造一个可变大小的队列
为空闲链表初始分配 n 个节点
要求 |
不能指定 capacity<> 参数 |
queue(const queue &) = delete;
queue & operator=(const queue &) = delete;
queue(queue &&) = delete;
queue & operator=(queue &&) = delete;
void reserve(size_type n);
为链表分配 n 个节点
![]() |
注意 |
---|---|
线程安全,如果内存分配器阻塞,可能会阻塞 |
要求 |
仅当未给出 capacity<> 参数时有效 |
void reserve_unsafe(size_type n);
为链表分配 n 个节点
![]() |
注意 |
---|---|
非线程安全,如果内存分配器阻塞,可能会阻塞 |
要求 |
仅当未给出 capacity<> 参数时有效 |
~queue(void);
销毁队列,释放空闲链表中的所有节点。
bool empty(void) const;
检查队列是否为空
![]() |
注意 |
---|---|
结果仅在没有其他线程修改队列时准确。因此,在程序逻辑中很少使用此值。 |
返回 |
如果队列为空,则为 true,否则为 false |
bool push(const T & t);
将对象 t 推入队列。
![]() |
注意 |
---|---|
线程安全。如果内部内存池耗尽且内存池不是固定大小的,将从操作系统分配一个新节点。这可能不是无锁的。 |
后置条件 |
如果可以分配内部节点,则对象将被推入队列 |
返回 |
如果推送操作成功,则为 |
bool push(T && t);
将对象 t 推入队列。
![]() |
注意 |
---|---|
线程安全。如果内部内存池耗尽且内存池不是固定大小的,将从操作系统分配一个新节点。这可能不是无锁的。 |
后置条件 |
如果可以分配内部节点,则对象将被推入队列 |
返回 |
如果推送操作成功,则为 |
bool bounded_push(const T & t);
将对象 t 推入队列。
![]() |
注意 |
---|---|
线程安全且非阻塞。如果内部内存池耗尽,操作将失败 |
后置条件 |
如果可以分配内部节点,则对象将被推入队列 |
返回 |
如果推送操作成功,则为 |
抛出 |
如果内存分配器抛出异常 |
bool bounded_push(T && t);
将对象 t 推入队列。
![]() |
注意 |
---|---|
线程安全且非阻塞。如果内部内存池耗尽,操作将失败 |
后置条件 |
如果可以分配内部节点,则对象将被推入队列 |
返回 |
如果推送操作成功,则为 |
抛出 |
如果内存分配器抛出异常 |
bool unsynchronized_push(T && t);
将对象 t 推入队列。
![]() |
注意 |
---|---|
非线程安全。如果内部内存池耗尽且内存池不是固定大小的,将从操作系统分配一个新节点。这可能不是无锁的。 |
后置条件 |
如果可以分配内部节点,则对象将被推入队列 |
返回 |
如果推送操作成功,则为 |
抛出 |
如果内存分配器抛出异常 |
bool pop(T & ret);
从队列中弹出对象。
![]() |
注意 |
---|---|
线程安全且非阻塞。即使操作失败,也可能修改返回参数。 |
后置条件 |
如果弹出操作成功,对象将被复制到 ret。 |
返回 |
如果弹出操作成功,则为 true,如果队列为空,则为 false。 |
template<typename U> bool pop(U & ret);
从队列中弹出对象。
![]() |
注意 |
---|---|
线程安全且非阻塞。即使操作失败,也可能修改返回参数。 |
要求 |
类型 U 必须可以通过 T 构建和复制,或者 T 必须可转换为 U |
后置条件 |
如果弹出操作成功,对象将被复制到 ret。 |
返回 |
如果弹出操作成功,则为 true,如果队列为空,则为 false。 |
std::optional< T > pop(uses_optional_t);
从队列中弹出对象,并返回一个 std::optional<>
![]() |
注意 |
---|---|
线程安全且非阻塞 |
返回 |
成功时带有值的 |
template<typename U> std::optional< U > pop(uses_optional_t);
从队列中弹出对象,并返回一个 std::optional<>
![]() |
注意 |
---|---|
线程安全且非阻塞 |
要求 |
类型 |
返回 |
成功时带有值的 |
bool unsynchronized_pop(T & ret);
从队列中弹出对象。
![]() |
注意 |
---|---|
非线程安全,但非阻塞。即使操作失败,也可能修改返回参数。 |
后置条件 |
如果弹出操作成功,对象将被复制到 ret。 |
返回 |
如果弹出操作成功,则为 true,如果队列为空,则为 false。 |
template<typename U> bool unsynchronized_pop(U & ret);
从队列中弹出对象。
![]() |
注意 |
---|---|
非线程安全,但非阻塞。即使操作失败,也可能修改返回参数。 |
要求 |
类型 U 必须可以通过 T 构建和复制,或者 T 必须可转换为 U |
后置条件 |
如果弹出操作成功,对象将被复制到 ret。 |
返回 |
如果弹出操作成功,则为 true,如果队列为空,则为 false。 |
template<typename Functor> bool consume_one(Functor && f);
通过 functor 消耗一个元素
从队列中弹出单个元素,并对该对象应用函数对象
![]() |
注意 |
---|---|
线程安全且非阻塞,前提是 functor 线程安全且非阻塞。 |
返回 |
如果消耗了一个元素,则为 |
template<typename Functor> size_t consume_all(Functor && f);
通过 functor 消耗所有元素
依次从队列中弹出所有元素,并对每个对象应用函数对象
![]() |
注意 |
---|---|
线程安全且非阻塞,前提是 functor 线程安全且非阻塞。 |
返回 |
被消耗的元素数量 |