Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Customizing Boost.Interprocess

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 16. Boost.Interprocess

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Если алгоритм по умолчанию не удовлетворяет требованиям пользователей, легко предоставить различные алгоритмы, такие как растровое отображение или более продвинутые сегрегированные списки для удовлетворения требований. Класс, реализующий алгоритм, должен быть совместим с общей памятью, поэтому он не должен иметь никакой виртуальной функции или виртуального наследования или любого косвенного базового класса с виртуальной функцией или наследованием.

Это интерфейс, который должен быть реализован:

class my_algorithm
{
   public:
   //!The mutex type to be used by the rest of Interprocess framework
   typedef implementation_defined   mutex_family;
   //!The pointer type to be used by the rest of Interprocess framework
   typedef implementation_defined   void_pointer;
   //!Constructor. "size" is the total size of the managed memory segment,
   //!"extra_hdr_bytes" indicates the extra bytes after the sizeof(my_algorithm)
   //!that the allocator should not use at all.
   my_algorithm (std::size_t size, std::size_t extra_hdr_bytes);
   //!Obtains the minimum size needed by the algorithm
   static std::size_t get_min_size (std::size_t extra_hdr_bytes);
   //!Allocates bytes, returns 0 if there is not more memory
   void* allocate (std::size_t nbytes);
   //!Deallocates previously allocated bytes
   void  deallocate (void *adr);
   //!Returns the size of the memory segment
   std::size_t get_size()  const;
   //!Increases managed memory in extra_size bytes more
   void grow(std::size_t extra_size);
   /*...*/
};

Давайте посмотрим на публичные типдефы, чтобы определить:

typedef /* . . . */ void_pointer;
typedef /* . . . */ mutex_family;

<void_pointer>typedef определяет тип указателя, который будет использоваться вBoost.Interprocessфреймворк, использующий алгоритм. Например, если определить

typedef void * void_pointer;

ВсеBoost.Interprocessфреймворк, использующий этот алгоритм, будет использовать необработанные указатели в качестве членов. Но если мы определим:

typedef offset_ptr<void> void_pointer;

Тогда всеBoost.Interprocessframework будет использовать относительные указатели.

<mutex_family>представляет собой структуру, содержащую типдефы для различных типов interprocess_mutex, которые будут использоваться в.Усилить межпроцессныйфреймворк. Например, определенная

struct mutex_family
{
   typedef boost::interprocess::interprocess_mutex             mutex_type;
   typedef boost::interprocess::interprocess_recursive_mutex   recursive_mutex_type;
};

Определяет все типы interprocess_mutex с помощью boost::interprocess interprocess_mutex types. Пользователь может указать желаемое семейство mutex.

typedef mutex_family mutex_family;

Новый алгоритм (назовем егоmy_algorithm) должен реализовать все функции, которые повышают::interprocess:::rbtree_best_fit класс предлагает:

  • мой алгоритмконструктор должен принять 2 аргумента:
    • размеруказывает общий размер управляемого сегмента памяти, иmy_algorithmобъект всегда будет сконструирован со смещением 0 сегмента памяти.
    • Параметрextra_hdr_bytesуказывает количество байтов после смещения<sizeof(my_algorithm)>, котороемой_алгоритмвообще не может использовать. Эти дополнительные байты будут использоваться для хранения дополнительных данных, которые не должны быть перезаписаны. Итак,мой_алгоритмбудет размещен по адресу XXX сегмента памяти, и будет управлять[XXX + размер(my_algorithm) + extra_hdr_bytes, XXX + размер)диапазон сегмента.
  • get_min_size()функция должна возвращать минимальное пространство, необходимое алгоритму, с пройденнымпараметром extra_hdr_bytes. Эта функция будет использоваться для проверки того, достаточно ли большой сегмент памяти для размещения алгоритма.
  • Выделить()функция должна вернуться 0, если больше нет доступной памяти. Память, возвращаемая посредствомmy_algorithm, должна быть выровнена с наиболее ограничительным выравниванием памяти системы. Эта функция должна выполняться с возможностями синхронизации, предлагаемыми<typename mutex_family::mutex_type>interprocess_mutex. Это означает, что если мы определим<typedef mutex_familymutex_family;>, то эта функция должна обеспечивать такую же синхронизацию, как если бы она была окружена блокировкой / разблокировкой interprocess_mutex. Обычно это реализуется с использованием элемента типа<mutex_family::mutex_type>, но это может быть сделано с использованием атомных инструкций или алгоритмов блокировки.
  • [править править код]функция должна обеспечивать наличие возвращенного буфера для новых ассигнований. Эта функция должна обеспечивать ту же синхронизацию, что и<allocate()>.
  • Размер()функция возвращает пройденныйразмерпараметр в конструкторе.мой алгоритмдолжен хранить размер внутри.
  • Растутфункция расширит управляемую память наmy_algorithmвextra_sizeбайтах.Размерфункция должна возвращать обновленный размер, и новый управляемый диапазон памяти будет (если адрес, где построен алгоритм XXX):[XXX + sizeof(my_algorithm) + extra_hdr_bytes, XXX + old_size + extra_size). Эта функция должна обеспечивать ту же синхронизацию, что и<allocate()>.

Вот так. Теперь мы можем создать новую управляемую общую память, используя наш новый алгоритм:

//Managed memory segment to allocate named (c-string) objects
//using a user-defined memory allocation algorithm
basic_managed_shared_memory<char,
                         ,my_algorithm
                         ,flat_map_index>
   my_managed_shared_memory;

Если предоставленные STL-подобные распределители не удовлетворяют потребности пользователя, пользователь может реализовать другой STL-совместимый распределитель, используя необработанное распределение памяти и названные функции построения объектов. Таким образом, пользователь может реализовать более подходящие схемы распределения поверх базовых схем распределения совместно используемой памяти, подобно тому, как более сложные распределители построены поверх новых функций.

При использовании сегмента управляемой памятиget_segment_manager()функция возвращает указатель менеджеру сегмента. С помощью этого указателя выделение необработанной памяти и названные функции построения объектов можно назвать непосредственно:

//Create the managed shared memory and initialize resources
managed_shared_memory segment
   (create_only
   ,"/MySharedMemory"   //segment name
   ,65536);             //segment size in bytes
//Obtain the segment manager
managed_shared_memory::segment_manager *segment_mngr
   = segment.get_segment_manager();
//With the segment manager, now we have access to all allocation functions
segment_mngr->deallocate(segment_mngr->allocate(32));
segment_mngr->construct<int>("My_Int")[32](0);
segment_mngr->destroy<int>("My_Int");
//Initialize the custom, managed memory segment compatible
//allocator with the segment manager.
//
//MySTLAllocator uses segment_mngr->xxx functions to
//implement its allocation scheme
MySTLAllocator<int> stl_alloc(segment_mngr);
//Alias a new vector type that uses the custom STL compatible allocator
typedef std::vector<int, MySTLAllocator<int> > MyVect;
//Construct the vector in shared memory with the allocator as constructor parameter
segment.construct<MyVect>("MyVect_instance")(stl_alloc);

Пользователь может создавать новые STL-совместимые распределители, которые используют менеджер сегментов для доступа ко всем функциям управления памятью/конструкции объектов. ВсеBoost.Interprocess' STL совместимые распределители основаны на этом подходе.Помните, что для совместимости с управляемыми сегментами памяти распределители должны определять свойуказательтипдеф как то же семейство указателей, что и<segment_manager::void_pointer>типдеф. Это означает, что если<segment_manager::void_pointer><offset_ptr<void>>,<MySTLAllocator<int>>следует определить<pointer>как<offset_ptr<int>>. Причина этого в том, что распределители являются членами контейнеров, и если мы хотим поместить контейнер в управляемый сегмент памяти, распределитель должен быть готов к этому.

Сегмент управляемой памяти использует индекс имени/объекта для ускорения поиска и создания объектов. Специализации по умолчанию сегментов управляемой памяти (например,<managed_shared_memory>), используют<boost::interprocess::flat_map>в качестве индекса.

Однако тип индекса может быть выбран с помощью параметра шаблона, чтобы пользователь мог определить свой собственный тип индекса, если ему это нужно. Чтобы построить новый тип индекса, пользователь должен создать класс со следующими рекомендациями:

  • Интерфейс индекса должен следовать общему публичному интерфейсу std::map и std::tr1::unordered_map, включая публичные типдефы. Типовой индекс<value_type>может быть типа:
std::pair<key_type, mapped_type>

или

std::pair<const key_type, mapped_type>

Чтобы упорядоченные массивы или деке могли использоваться в качестве типов индексов. Некоторые известные классы, следующие этому базовому интерфейсу, являются<boost::unordered_map>,<boost::interprocess::flat_map>и<boost::interprocess::map>.

  • Класс должен быть шаблоном класса, принимающим только структуру черт этого типа:
struct index_traits
{
   typedef /*...*/   key_type;
   typedef /*...*/   mapped_type;
   typedef /*...*/   segment_manager;
};
template <class IndexTraits>
class my_index_type;

<key_type>типдеф пройденного<index_traits>будет специализацией следующего класса:

//!The key of the named allocation information index. Stores a to
//!a null string and the length of the string to speed up sorting
template<...>
struct index_key
{
   typedef /*...*/                              char_type;
   typedef /*...*/                              const_char_ptr_t;
   //Pointer to the object's name (null terminated)
   const_char_ptr_t                             mp_str;
   //Length of the name buffer (null NOT included)
   std::size_t                                  m_len;
   //!Constructor of the key
   index_key (const CharT *name, std::size_t length);
   //!Less than function for index ordering
   bool operator < (const index_key & right) const;
   //!Equal to function for index ordering
   bool operator == (const index_key & right) const;
};

<mapped_type>непосредственно не изменяется настроенным индексом, но он необходим для определения типа индекса.segment_managerбудет типом менеджера сегмента, который будет управлять индексом.<segment_manager>будет определять интересные внутренние типы, такие как<void_pointer>или<mutex_family>.

  • Конструктор настроенного типа индекса должен использовать указатель в качестве аргумента конструктора для segment_manager:
constructor(segment_manager *segment_mngr);
  • Индекс должен обеспечивать функцию резервирования памяти, которая оптимизирует индекс, если пользователь знает количество элементов, подлежащих вставке в индекс:
void reserve(std::size_t n);

Например, тип индекса<flat_map_index>, основанный на<boost::interprocess::flat_map>, определяется как:

namespace boost { namespace interprocess {
#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Helper class to define typedefs from IndexTraits
template <class MapConfig>
struct flat_map_index_aux
{
   typedef typename MapConfig::key_type            key_type;
   typedef typename MapConfig::mapped_type         mapped_type;
   typedef typename MapConfig::
      segment_manager_base                   segment_manager_base;
   typedef std::less<key_type>                     key_less;
   typedef std::pair<key_type, mapped_type>        value_type;
   typedef allocator<value_type
                    ,segment_manager_base>   allocator_type;
   typedef flat_map<key_type,  mapped_type,
                    key_less, allocator_type>      index_t;
};
#endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Index type based in flat_map. Just derives from flat_map and
//!defines the interface needed by managed memory segments.
template <class MapConfig>
class flat_map_index
   //Derive class from flat_map specialization
   : public flat_map_index_aux<MapConfig>::index_t
{
   #if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
   typedef flat_map_index_aux<MapConfig>  index_aux;
   typedef typename index_aux::index_t    base_type;
   typedef typename index_aux::
      segment_manager_base          segment_manager_base;
   #endif   //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
   public:
   //!Constructor. Takes a pointer to the segment manager. Can throw
   flat_map_index(segment_manager_base *segment_mngr)
      : base_type(typename index_aux::key_less(),
                  typename index_aux::allocator_type(segment_mngr))
   {}
   //!This reserves memory to optimize the insertion of n elements in the index
   void reserve(typename segment_manager_base::size_type n)
   {  base_type::reserve(n);  }
   //!This frees all unnecessary memory
   void shrink_to_fit()
   {  base_type::shrink_to_fit();   }
};
}}   //namespace boost { namespace interprocess

Если пользователь определяет индекс контейнера узла (контейнер, итераторы которого не являются недействительными при вставке или стирании других элементов),Boost.Interprocessможет оптимизировать именованное разрушение объекта при разрушении с помощью указателя.Boost.Interprocessможет хранить итератор рядом с объектом и вместо использования имени объекта для стирания индексной записи использует итератор, который является более быстрой операцией. Таким образом, если вы создаете новый индекс контейнера узла (например, дерево), вы должны определить специализацию<boost::interprocess::is_node_index<...>>, определенную в<<boost/interprocess/detail/utilities.hpp>>:

//!Trait classes to detect if an index is a node
//!index. This allows more efficient operations
//!when deallocating named objects.
template<class MapConfig>
struct is_node_index
   <my_index<MapConfig> >
{
   static const bool value = true;
};

Interprocess также определяет другие типы индексов:

  • boost::map_indexиспользуетboost::interprocess::mapв качестве индексного типа.
  • boost::null_index, который использует тип фиктивного индекса, если пользователю просто нужны анонимные ассигнования и он хочет сохранить некоторое пространство и классы.

Определить новый сегмент управляемой памяти, который использует новый индекс, легко. Например, новая управляемая общая память, которая использует новый индекс:

//!Defines a managed shared memory with a c-strings as
//!a keys, the red-black tree best fit algorithm (with process-shared mutexes
//!and offset_ptr pointers) as raw shared memory management algorithm
//!and a custom index
typedef
   basic_managed_shared_memory <
                              char,
                              rbtree_best_fit<mutex_family>,
                              my_index_type
                             >
   my_managed_shared_memory;

PrevUpHomeNext

Статья Customizing Boost.Interprocess раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 16. Boost.Interprocess может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 16. Boost.Interprocess ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 05:22:00/0.0071890354156494/0