adaptive_node_pool.hpp

来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 655 行 · 第 1/2 页

HPP
655
字号
         m_block_multiset.erase_and_dispose            (it, block_destroyer(this));      }   }   void priv_reinsert_nodes_in_block(multiallocation_iterator it)   {      multiallocation_iterator itend;      block_iterator block_it(m_block_multiset.end());      while(it != itend){         void *pElem = &*it;         ++it;         priv_invariants();         block_info_t *block_info = this->priv_block_from_node(pElem);         assert(block_info->free_nodes.size() < m_real_num_node);         //We put the node at the beginning of the free node list         node_t * to_deallocate = static_cast<node_t*>(pElem);         block_info->free_nodes.push_front(*to_deallocate);         block_iterator this_block(block_multiset_t::s_iterator_to(*block_info));         block_iterator next_block(this_block);         ++next_block;         //Cache the free nodes from the block         std::size_t this_block_free_nodes = this_block->free_nodes.size();         if(this_block_free_nodes == 1){            m_block_multiset.insert(m_block_multiset.begin(), *block_info);         }         else{            block_iterator next_block(this_block);            ++next_block;            if(next_block != block_it){               std::size_t next_free_nodes = next_block->free_nodes.size();               if(this_block_free_nodes > next_free_nodes){                  //Now move the block to the new position                  m_block_multiset.erase(this_block);                  m_block_multiset.insert(*block_info);               }            }         }         //Update free block count         if(this_block_free_nodes == m_real_num_node){            ++m_totally_free_blocks;         }         priv_invariants();      }   }   node_t *priv_take_first_node()   {      assert(m_block_multiset.begin() != m_block_multiset.end());      //We take the first free node the multiset can't be empty      free_nodes_t &free_nodes = m_block_multiset.begin()->free_nodes;      node_t *first_node = &free_nodes.front();      const std::size_t free_nodes_count = free_nodes.size();      assert(0 != free_nodes_count);      free_nodes.pop_front();      if(free_nodes_count == 1){         m_block_multiset.erase(m_block_multiset.begin());      }      else if(free_nodes_count == m_real_num_node){         --m_totally_free_blocks;      }      priv_invariants();      return first_node;   }   class block_destroyer;   friend class block_destroyer;   class block_destroyer   {      public:      block_destroyer(const private_adaptive_node_pool_impl *impl)         :  mp_impl(impl)      {}      void operator()(typename block_multiset_t::pointer to_deallocate)      {         std::size_t free_nodes = to_deallocate->free_nodes.size();         (void)free_nodes;         assert(free_nodes == mp_impl->m_real_num_node);         assert(0 == to_deallocate->hdr_offset);         hdr_offset_holder *hdr_off_holder = mp_impl->priv_first_subblock_from_block(detail::get_pointer(to_deallocate));         mp_impl->mp_segment_mngr_base->deallocate(hdr_off_holder);      }      const private_adaptive_node_pool_impl *mp_impl;   };   //This macro will activate invariant checking. Slow, but helpful for debugging the code.   //#define BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS   void priv_invariants()   #ifdef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS   #undef BOOST_INTERPROCESS_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS   {      //We iterate through the block list to free the memory      block_iterator it(m_block_multiset.begin()),                      itend(m_block_multiset.end()), to_deallocate;      if(it != itend){         for(++it; it != itend; ++it){            block_iterator prev(it);            --prev;            std::size_t sp = prev->free_nodes.size(),                        si = it->free_nodes.size();            assert(sp <= si);            (void)sp;   (void)si;         }      }      {         //Check that the total free nodes are correct         it    = m_block_multiset.begin();         itend = m_block_multiset.end();         std::size_t total_free_nodes = 0;         for(; it != itend; ++it){            total_free_nodes += it->free_nodes.size();         }         assert(total_free_nodes >= m_totally_free_blocks*m_real_num_node);      }      {         //Check that the total totally free blocks are correct         it    = m_block_multiset.begin();         itend = m_block_multiset.end();         std::size_t total_free_blocks = 0;         for(; it != itend; ++it){            total_free_blocks += (it->free_nodes.size() == m_real_num_node);         }         assert(total_free_blocks == m_totally_free_blocks);      }      {      //Check that header offsets are correct      it = m_block_multiset.begin();      for(; it != itend; ++it){         hdr_offset_holder *hdr_off_holder = priv_first_subblock_from_block(&*it);         for(std::size_t i = 0, max = m_num_subblocks; i < max; ++i){            assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(&*it)- reinterpret_cast<char*>(hdr_off_holder)));            assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));            assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));            hdr_off_holder = reinterpret_cast<hdr_offset_holder *>(reinterpret_cast<char*>(hdr_off_holder) + m_real_block_alignment);         }      }      }   }   #else   {} //empty   #endif   //!Deallocates all used memory. Never throws   void priv_clear()   {      #ifndef NDEBUG      block_iterator it    = m_block_multiset.begin();      block_iterator itend = m_block_multiset.end();      std::size_t num_free_nodes = 0;      for(; it != itend; ++it){         //Check for memory leak         assert(it->free_nodes.size() == m_real_num_node);         ++num_free_nodes;      }      assert(num_free_nodes == m_totally_free_blocks);      #endif      priv_invariants();      m_block_multiset.clear_and_dispose         (block_destroyer(this));      m_totally_free_blocks = 0;   }   block_info_t *priv_block_from_node(void *node) const   {      hdr_offset_holder *hdr_off_holder =         reinterpret_cast<hdr_offset_holder*>((std::size_t)node & std::size_t(~(m_real_block_alignment - 1)));      assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));      assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));      block_info_t *block = reinterpret_cast<block_info_t *>         (reinterpret_cast<char*>(hdr_off_holder) + hdr_off_holder->hdr_offset);      assert(block->hdr_offset == 0);      return block;   }   hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block) const   {      hdr_offset_holder *hdr_off_holder = reinterpret_cast<hdr_offset_holder*>            (reinterpret_cast<char*>(block) - (m_num_subblocks-1)*m_real_block_alignment);      assert(hdr_off_holder->hdr_offset == std::size_t(reinterpret_cast<char*>(block) - reinterpret_cast<char*>(hdr_off_holder)));      assert(0 == ((std::size_t)hdr_off_holder & (m_real_block_alignment - 1)));      assert(0 == (hdr_off_holder->hdr_offset & (m_real_block_alignment - 1)));      return hdr_off_holder;   }   //!Allocates a several blocks of nodes. Can throw boost::interprocess::bad_alloc   void priv_alloc_block(std::size_t n)   {      std::size_t real_block_size = m_real_block_alignment*m_num_subblocks - SegmentManagerBase::PayloadPerAllocation;      std::size_t elements_per_subblock = (m_real_block_alignment - HdrOffsetSize)/m_real_node_size;      std::size_t hdr_subblock_elements   = (m_real_block_alignment - HdrSize - SegmentManagerBase::PayloadPerAllocation)/m_real_node_size;      for(std::size_t i = 0; i != n; ++i){         //We allocate a new NodeBlock and put it the last         //element of the tree         char *mem_address = static_cast<char*>            (mp_segment_mngr_base->allocate_aligned(real_block_size, m_real_block_alignment));         if(!mem_address)   throw std::bad_alloc();         ++m_totally_free_blocks;         //First initialize header information on the last subblock         char *hdr_addr = mem_address + m_real_block_alignment*(m_num_subblocks-1);         block_info_t *c_info = new(hdr_addr)block_info_t;         //Some structural checks         assert(static_cast<void*>(&static_cast<hdr_offset_holder*>(c_info)->hdr_offset) ==                static_cast<void*>(c_info));         typename free_nodes_t::iterator prev_insert_pos = c_info->free_nodes.before_begin();         for( std::size_t subblock = 0, maxsubblock = m_num_subblocks - 1            ; subblock < maxsubblock            ; ++subblock, mem_address += m_real_block_alignment){            //Initialize header offset mark            new(mem_address) hdr_offset_holder(std::size_t(hdr_addr - mem_address));            char *pNode = mem_address + HdrOffsetSize;            for(std::size_t i = 0; i < elements_per_subblock; ++i){               prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);               pNode   += m_real_node_size;            }         }         {            char *pNode = hdr_addr + HdrSize;            //We initialize all Nodes in Node Block to insert             //them in the free Node list            for(std::size_t i = 0; i < hdr_subblock_elements; ++i){               prev_insert_pos = c_info->free_nodes.insert_after(prev_insert_pos, *new (pNode) node_t);               pNode   += m_real_node_size;            }         }         //Insert the block after the free node list is full         m_block_multiset.insert(m_block_multiset.end(), *c_info);      }   }   private:   typedef typename pointer_to_other      <void_pointer, segment_manager_base_type>::type   segment_mngr_base_ptr_t;   const std::size_t m_max_free_blocks;   const std::size_t m_real_node_size;   //Round the size to a power of two value.   //This is the total memory size (including payload) that we want to   //allocate from the general-purpose allocator   const std::size_t m_real_block_alignment;   std::size_t m_num_subblocks;   //This is the real number of nodes per block   //const   std::size_t m_real_num_node;   segment_mngr_base_ptr_t                mp_segment_mngr_base;//Segment manager   block_multiset_t                       m_block_multiset;    //Intrusive block list   std::size_t                            m_totally_free_blocks;       //Free blocks};template< class SegmentManager        , std::size_t NodeSize        , std::size_t NodesPerBlock        , std::size_t MaxFreeBlocks        , unsigned char OverheadPercent        >class private_adaptive_node_pool   :  public private_adaptive_node_pool_impl         <typename SegmentManager::segment_manager_base_type>{   typedef private_adaptive_node_pool_impl      <typename SegmentManager::segment_manager_base_type> base_t;   //Non-copyable   private_adaptive_node_pool();   private_adaptive_node_pool(const private_adaptive_node_pool &);   private_adaptive_node_pool &operator=(const private_adaptive_node_pool &);   public:   typedef SegmentManager segment_manager;   static const std::size_t nodes_per_block = NodesPerBlock;   //Deprecated, use node_per_block   static const std::size_t nodes_per_chunk = NodesPerBlock;   //!Constructor from a segment manager. Never throws   private_adaptive_node_pool(segment_manager *segment_mngr)      :  base_t(segment_mngr, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent)   {}   //!Returns the segment manager. Never throws   segment_manager* get_segment_manager() const   {  return static_cast<segment_manager*>(base_t::get_segment_manager_base()); }};//!Pooled shared memory allocator using adaptive pool. Includes//!a reference count but the class does not delete itself, this is  //!responsibility of user classes. Node size (NodeSize) and the number of//!nodes allocated per block (NodesPerBlock) are known at compile timetemplate< class SegmentManager        , std::size_t NodeSize        , std::size_t NodesPerBlock        , std::size_t MaxFreeBlocks        , unsigned char OverheadPercent        >class shared_adaptive_node_pool    :  public detail::shared_pool_impl      < private_adaptive_node_pool         <SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>      >{   typedef detail::shared_pool_impl      < private_adaptive_node_pool         <SegmentManager, NodeSize, NodesPerBlock, MaxFreeBlocks, OverheadPercent>      > base_t;   public:   shared_adaptive_node_pool(SegmentManager *segment_mgnr)      : base_t(segment_mgnr)   {}};}  //namespace detail {}  //namespace interprocess {}  //namespace boost {#include <boost/interprocess/detail/config_end.hpp>#endif   //#ifndef BOOST_INTERPROCESS_DETAIL_ADAPTIVE_NODE_POOL_HPP

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?