Modify experimental "allocate_many" function to take an alignment parameter.

This commit is contained in:
Ion Gaztañaga
2026-01-10 18:58:01 +01:00
parent 5069b61f65
commit aab8703240
8 changed files with 112 additions and 99 deletions

View File

@@ -3986,7 +3986,7 @@ Here is a small example showing how aligned allocation is used:
[section:managed_memory_segment_multiple_allocations Multiple allocation functions]
[caution This feature is experimental, interface and ABI are unstable]
[caution This feature is experimental, API and ABI are unstable]
If an application needs to allocate a lot of memory buffers but it needs
to deallocate them independently, the application is normally forced to loop
@@ -6875,6 +6875,12 @@ thank them:
* Added `BOOST_HEADER_DEPRECATED` to `<boost/interprocess/containers/*.hpp> headers. They were deprecated several releases ago, but this
message will annoy existing users to switch to Boost.Container headers.
* Changed the interface of [link managed_memory_segment_advanced_features.managed_memory_segment_multiple_allocations Multiple allocation functions]
(still experimental and API/ABI unstable) to support alignment.
Added `BOOST_HEADER_DEPRECATED` to `<boost/interprocess/containers/*.hpp> headers. They were deprecated several releases ago, but this
message will annoy existing users to switch to Boost.Container headers.
* Fixed bugs:
* [@https://github.com/boostorg/interprocess/issues/242 GitHub #242 (['"Cygwin compatibility issues"])].
* [@https://github.com/boostorg/interprocess/issues/247 GitHub #247 (['"destruction of move-constructed map using private_adaptive_pool triggers Assertion"])].

View File

@@ -38,9 +38,9 @@ int main()
managed_shared_memory managed_shm(create_only,test::get_process_id_name(), 65536);
//Allocate 16 elements of 100 bytes in a single call. Non-throwing version.
//Allocate 16 elements of 100 bytes with a minimal alignment of 4, in a single call. Non-throwing version.
multiallocation_chain chain;
managed_shm.allocate_many(std::nothrow, 100, 16, chain);
managed_shm.allocate_many(std::nothrow, 100, 16, 4u, chain);
//Check if the memory allocation was successful
if(chain.empty()) return 1;
@@ -68,7 +68,7 @@ int main()
for(std::size_t i = 0; i < 10; ++i)
sizes[i] = i*3;
managed_shm.allocate_many(sizes, 10, 1, chain);
managed_shm.allocate_many(sizes, 10, 1, 4, chain);
managed_shm.deallocate_many(chain);
return 0;
}

View File

@@ -307,24 +307,24 @@ class basic_managed_memory_impl
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(elem_bytes, n_elements, chain); }
void allocate_many(size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain)
{ mp_header->allocate_many(elem_bytes, n_elements, alignment, chain); }
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, chain); }
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{ mp_header->allocate_many(element_lengths, n_elements, sizeof_element, alignment, chain); }
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_bytes, n_elements, chain); }
void allocate_many(const std::nothrow_t &tag, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_bytes, n_elements, alignment, chain); }
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, chain); }
void allocate_many(const std::nothrow_t &tag, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{ mp_header->allocate_many(tag, elem_sizes, n_elements, sizeof_element, alignment, chain); }
//!Deallocates all elements contained in chain.
//!Never throws.

View File

@@ -125,9 +125,9 @@ class memory_algorithm_common
{ return get_rounded_size(size, Alignment); }
static void allocate_many
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
(MemoryAlgorithm *memory_algo, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain)
{
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, 0, chain);
return this_type::priv_allocate_many(memory_algo, &elem_bytes, n_elements, alignment, 0, chain);
}
static void deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain &chain)
@@ -235,9 +235,10 @@ class memory_algorithm_common
, const size_type *elem_sizes
, size_type n_elements
, size_type sizeof_element
, size_type alignment
, multiallocation_chain &chain)
{
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, chain);
this_type::priv_allocate_many(memory_algo, elem_sizes, n_elements, sizeof_element, alignment, chain);
}
static void* allocate_aligned(MemoryAlgorithm * const memory_algo, const size_type nbytes, const size_type alignment)
@@ -487,6 +488,7 @@ class memory_algorithm_common
( MemoryAlgorithm *memory_algo
, const size_type *elem_sizes
, size_type n_elements
, size_type alignment
, size_type sizeof_element
, multiallocation_chain &chain)
{
@@ -530,7 +532,7 @@ class memory_algorithm_common
size_type received_size = total_bytes;
void *ignore_reuse = 0;
void *ret = memory_algo->priv_allocate
(boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse);
(boost::interprocess::allocate_new, min_allocation, received_size, ignore_reuse, 1, alignment);
if(!ret){
break;
}

View File

@@ -157,22 +157,22 @@ class simple_seq_fit_impl
//!Multiple element allocation, same size
//!Experimental. Dont' use
void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain)
void allocate_many(size_type elem_bytes, size_type num_elements, size_type alignment, multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain);
algo_impl_t::allocate_many(this, elem_bytes, num_elements, alignment, chain);
}
//!Multiple element allocation, different size
//!Experimental. Dont' use
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
//-----------------------
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain);
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, alignment, chain);
}
//!Multiple element deallocation
@@ -229,7 +229,7 @@ class simple_seq_fit_impl
//!Real allocation algorithm with min allocation option
void * priv_allocate(boost::interprocess::allocation_type command
,size_type min_size
,size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object = Alignment);
,size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type sizeof_object = 1, size_type alignof_object = Alignment);
//!Returns the number of total units that a user buffer
//!of "userbytes" bytes really occupies (including header)
@@ -635,7 +635,7 @@ simple_seq_fit_impl<MutexFamily, VoidPointer>::
template<class MutexFamily, class VoidPointer>
void * simple_seq_fit_impl<MutexFamily, VoidPointer>::
priv_allocate(boost::interprocess::allocation_type command
,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type alignof_object)
,size_type limit_size, size_type &prefer_in_recvd_out_size, void *&reuse_ptr, size_type /*sizeof_object*/, size_type alignof_object)
{
//Backwards expansion not supported
command &= ~boost::interprocess::expand_bwd;

View File

@@ -204,22 +204,22 @@ class rbtree_best_fit
//!Multiple element allocation, same size
//!Experimental. Dont' use
void allocate_many(size_type elem_bytes, size_type num_elements, multiallocation_chain &chain)
void allocate_many(size_type elem_bytes, size_type num_elements, size_type alignment, multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
algo_impl_t::allocate_many(this, elem_bytes, num_elements, chain);
algo_impl_t::allocate_many(this, elem_bytes, num_elements, alignment, chain);
}
//!Multiple element allocation, different size
//!Experimental. Dont' use
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
void allocate_many(const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{
//-----------------------
boost::interprocess::scoped_lock<mutex_type> guard(m_header);
//-----------------------
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, chain);
algo_impl_t::allocate_many(this, elem_sizes, n_elements, sizeof_element, alignment, chain);
}
//!Multiple element allocation, different size

View File

@@ -210,10 +210,10 @@ class segment_manager_base
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
void allocate_many(size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain);
MemoryAlgorithm::allocate_many(elem_bytes, n_elements, alignment, chain);
if(!elem_bytes || chain.size() == prev_size){
throw bad_alloc();
}
@@ -222,10 +222,10 @@ class segment_manager_base
//Experimental. Don't use.
//!Allocates n_elements, each one of element_lengths[i]*sizeof_element bytes.
//!Throws bad_alloc on failure. chain.size() is not increased on failure.
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
void allocate_many(const size_type *element_lengths, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{
size_type prev_size = chain.size();
MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, chain);
MemoryAlgorithm::allocate_many(element_lengths, n_elements, sizeof_element, alignment, chain);
if(!sizeof_element || chain.size() == prev_size){
throw bad_alloc();
}
@@ -234,15 +234,15 @@ class segment_manager_base
//Experimental. Don't use.
//!Allocates n_elements of elem_bytes bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_bytes, n_elements, chain); }
void allocate_many(const std::nothrow_t &, size_type elem_bytes, size_type n_elements, size_type alignment, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_bytes, n_elements, alignment, chain); }
//Experimental. Don't use.
//!Allocates n_elements, each one of
//!element_lengths[i]*sizeof_element bytes.
//!Non-throwing version. chain.size() is not increased on failure.
void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, chain); }
void allocate_many(const std::nothrow_t &, const size_type *elem_sizes, size_type n_elements, size_type sizeof_element, size_type alignment, multiallocation_chain &chain)
{ MemoryAlgorithm::allocate_many(elem_sizes, n_elements, sizeof_element, alignment, chain); }
//Experimental. Don't use.
//!Deallocates all elements contained in chain.

View File

@@ -700,10 +700,11 @@ bool test_many_equal_allocation(SegMngr &sm)
return false;
typedef typename SegMngr::multiallocation_chain multiallocation_chain;
for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u) {
std::vector<void*> buffers;
for(std::size_t i = 0; true; ++i){
multiallocation_chain chain;
sm.allocate_many(std::nothrow, i+1, (i+1)*2, chain);
sm.allocate_many(std::nothrow, i+1, (i+1)*2, al, chain);
if(chain.empty())
break;
@@ -767,6 +768,7 @@ bool test_many_equal_allocation(SegMngr &sm)
sm.all_memory_deallocated() && sm.check_sanity();
if(!ok) return ok;
}
}
return true;
}
@@ -776,12 +778,13 @@ template<class SegMngr>
bool test_many_different_allocation(SegMngr &sm)
{
typedef typename SegMngr::multiallocation_chain multiallocation_chain;
const std::size_t ArraySize = 11;
const std::size_t ArraySize = 22;
typename SegMngr::size_type requested_sizes[ArraySize];
for(std::size_t i = 0; i < ArraySize; ++i){
requested_sizes[i] = 4*i;
}
for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u)
for( deallocation_type t = DirectDeallocation
; t != EndDeallocationType
; t = (deallocation_type)((int)t + 1)){
@@ -791,7 +794,9 @@ bool test_many_different_allocation(SegMngr &sm)
//Allocate buffers with extra memory
for(std::size_t i = 0; true; ++i){
void *ptr = sm.allocate(i, std::nothrow);
void *ptr = al > SegMngr::MemAlignment
? sm.allocate_aligned(i, al, std::nothrow)
: sm.allocate(i, std::nothrow);
if(!ptr)
break;
std::size_t size = sm.size(ptr);
@@ -813,7 +818,7 @@ bool test_many_different_allocation(SegMngr &sm)
std::vector<void*> buffers;
while(true){
multiallocation_chain chain;
sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, al, chain);
if(chain.empty())
break;
typename multiallocation_chain::size_type n = chain.size();
@@ -881,8 +886,6 @@ bool test_many_different_allocation(SegMngr &sm)
template<class SegMngr>
bool test_many_deallocation(SegMngr &sm)
{
typedef typename SegMngr::multiallocation_chain multiallocation_chain;
typedef typename SegMngr::multiallocation_chain multiallocation_chain;
const std::size_t ArraySize = 11;
boost::container::vector<multiallocation_chain> buffers;
@@ -892,10 +895,11 @@ bool test_many_deallocation(SegMngr &sm)
}
typename SegMngr::size_type free_memory = sm.get_free_memory();
for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u)
{
while(true){
multiallocation_chain chain;
sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
sm.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, al, chain);
if(chain.empty())
break;
buffers.push_back(boost::move(chain));
@@ -909,10 +913,11 @@ bool test_many_deallocation(SegMngr &sm)
if(!ok) return ok;
}
for(std::size_t al = 1; al <= SegMngr::MemAlignment*32u; al *= 2u)
{
for(std::size_t i = 0; true; ++i){
multiallocation_chain chain;
sm.allocate_many(std::nothrow, i*4, ArraySize, chain);
sm.allocate_many(std::nothrow, i*4, ArraySize, al, chain);
if(chain.empty())
break;
buffers.push_back(boost::move(chain));