From 18188f0937211276b9a677de1651a03ab0dd5fc0 Mon Sep 17 00:00:00 2001 From: YexuanXiao Date: Mon, 23 Sep 2024 13:11:24 +0800 Subject: [PATCH] Stateful allocator support for concurrent_queue and concurrent_bounded_queue --- include/oneapi/tbb/concurrent_queue.h | 82 +++++++++++-------- .../tbb/detail/_concurrent_queue_base.h | 8 +- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/include/oneapi/tbb/concurrent_queue.h b/include/oneapi/tbb/concurrent_queue.h index cfd5db6a550..c7486a616f0 100644 --- a/include/oneapi/tbb/concurrent_queue.h +++ b/include/oneapi/tbb/concurrent_queue.h @@ -137,25 +137,29 @@ class concurrent_queue { } concurrent_queue& operator=( const concurrent_queue& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_copy_assignment - if (my_queue_representation != other.my_queue_representation) { - clear(); + if (my_queue_representation != other.my_queue_representation) + return *this; + clear(); + if (queue_allocator_traits::propagate_on_container_move_assignment::value) { my_allocator = other.my_allocator; - my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item); } + my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item); return *this; } concurrent_queue& operator=( concurrent_queue&& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_move_assignment - if (my_queue_representation != other.my_queue_representation) { - clear(); + if (my_queue_representation == other.my_queue_representation) + return *this; + clear(); + if (queue_allocator_traits::propagate_on_container_move_assignment::value) { + my_allocator = std::move(other.my_allocator); + internal_swap(other); + } else { if (my_allocator == other.my_allocator) { internal_swap(other); } else { - my_queue_representation->assign(*other.my_queue_representation, other.my_allocator, move_construct_item); + my_queue_representation->assign(*other.my_queue_representation, my_allocator, move_construct_item); other.clear(); - my_allocator = std::move(other.my_allocator); } } return *this; @@ -178,8 +182,12 @@ class concurrent_queue { } void swap ( concurrent_queue& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_swap - __TBB_ASSERT(my_allocator == other.my_allocator, "unequal allocators"); + if (queue_allocator_traits::propagate_on_container_swap::value) { + using std::swap; + swap(my_allocator, other.my_allocator); + } else { + __TBB_ASSERT(my_allocator == other.my_allocator, "unequal allocators"); + } internal_swap(other); } @@ -253,15 +261,13 @@ class concurrent_queue { template friend class concurrent_queue_iterator; - static void copy_construct_item(T* location, const void* src) { - // TODO: use allocator_traits for copy construction - new (location) value_type(*static_cast(src)); - // queue_allocator_traits::construct(my_allocator, location, *static_cast(src)); + + static void copy_construct_item(queue_allocator_type& allocator, T* location, const void* src) { + queue_allocator_traits::construct(allocator, location, *static_cast(src)); } - static void move_construct_item(T* location, const void* src) { - // TODO: use allocator_traits for move construction - new (location) value_type(std::move(*static_cast(const_cast(src)))); + static void move_construct_item(queue_allocator_type& allocator, T* location, const void* src) { + queue_allocator_traits::construct(allocator, location, std::move(*static_cast(const_cast(src)))); } queue_allocator_type my_allocator; @@ -416,25 +422,29 @@ class concurrent_bounded_queue { } concurrent_bounded_queue& operator=( const concurrent_bounded_queue& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_copy_assignment - if (my_queue_representation != other.my_queue_representation) { - clear(); + if (my_queue_representation != other.my_queue_representation) + return *this; + clear(); + if (queue_allocator_traits::propagate_on_container_move_assignment::value) { my_allocator = other.my_allocator; - my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item); } + my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item); return *this; } concurrent_bounded_queue& operator=( concurrent_bounded_queue&& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_move_assignment - if (my_queue_representation != other.my_queue_representation) { - clear(); + if (my_queue_representation == other.my_queue_representation) + return *this; + clear(); + if (queue_allocator_traits::propagate_on_container_move_assignment::value) { + my_allocator = std::move(other.my_allocator); + internal_swap(other); + } else { if (my_allocator == other.my_allocator) { internal_swap(other); } else { - my_queue_representation->assign(*other.my_queue_representation, other.my_allocator, move_construct_item); + my_queue_representation->assign(*other.my_queue_representation, my_allocator, move_construct_item); other.clear(); - my_allocator = std::move(other.my_allocator); } } return *this; @@ -457,8 +467,12 @@ class concurrent_bounded_queue { } void swap ( concurrent_bounded_queue& other ) { - //TODO: implement support for std::allocator_traits::propagate_on_container_swap - __TBB_ASSERT(my_allocator == other.my_allocator, "unequal allocators"); + if (queue_allocator_traits::propagate_on_container_swap::value) { + using std::swap; + swap(my_allocator, other.my_allocator); + } else { + __TBB_ASSERT(my_allocator == other.my_allocator, "unequal allocators"); + } internal_swap(other); } @@ -641,14 +655,12 @@ class concurrent_bounded_queue { r1::abort_bounded_queue_monitors(my_monitors); } - static void copy_construct_item(T* location, const void* src) { - // TODO: use allocator_traits for copy construction - new (location) value_type(*static_cast(src)); + static void copy_construct_item(queue_allocator_type& ator, T* location, const void* src) { + queue_allocator_traits::construct(ator, location, *static_cast(src)); } - static void move_construct_item(T* location, const void* src) { - // TODO: use allocator_traits for move construction - new (location) value_type(std::move(*static_cast(const_cast(src)))); + static void move_construct_item(queue_allocator_type& ator, T* location, const void* src) { + queue_allocator_traits::construct(ator, location, std::move(*static_cast(const_cast(src)))); } template diff --git a/include/oneapi/tbb/detail/_concurrent_queue_base.h b/include/oneapi/tbb/detail/_concurrent_queue_base.h index ee628e1e89e..7a14bffc92f 100644 --- a/include/oneapi/tbb/detail/_concurrent_queue_base.h +++ b/include/oneapi/tbb/detail/_concurrent_queue_base.h @@ -103,7 +103,7 @@ class micro_queue { using page_allocator_traits = tbb::detail::allocator_traits; public: - using item_constructor_type = void (*)(value_type* location, const void* src); + using item_constructor_type = void (*)(queue_allocator_type&, value_type* location, const void* src); micro_queue() = default; micro_queue( const micro_queue& ) = delete; micro_queue& operator=( const micro_queue& ) = delete; @@ -254,7 +254,7 @@ class micro_queue { new_page->mask.store(src_page->mask.load(std::memory_order_relaxed), std::memory_order_relaxed); for (; begin_in_page!=end_in_page; ++begin_in_page, ++g_index) { if (new_page->mask.load(std::memory_order_relaxed) & uintptr_t(1) << begin_in_page) { - copy_item(*new_page, begin_in_page, *src_page, begin_in_page, construct_item); + copy_item(allocator, *new_page, begin_in_page, *src_page, begin_in_page, construct_item); } } return new_page; @@ -324,11 +324,11 @@ class micro_queue { ~destroyer() {my_value.~T();} }; // class destroyer - void copy_item( padded_page& dst, size_type dindex, const padded_page& src, size_type sindex, + void copy_item( queue_allocator_type& allocator, padded_page& dst, size_type dindex, const padded_page& src, size_type sindex, item_constructor_type construct_item ) { auto& src_item = src[sindex]; - construct_item( &dst[dindex], static_cast(&src_item) ); + construct_item( allocator, &dst[dindex], static_cast(&src_item) ); } void assign_and_destroy_item( void* dst, padded_page& src, size_type index ) {