Если алгоритм по умолчанию не удовлетворяет требованиям пользователей, легко предоставить различные алгоритмы, такие как растровое отображение или более продвинутые сегрегированные списки для удовлетворения требований. Класс, реализующий алгоритм, должен быть совместим с общей памятью, поэтому он не должен иметь никакой виртуальной функции или виртуального наследования или любого косвенного базового класса с виртуальной функцией или наследованием.
Это интерфейс, который должен быть реализован:
classmy_algorithm{public://!The mutex type to be used by the rest of Interprocess frameworktypedefimplementation_definedmutex_family;//!The pointer type to be used by the rest of Interprocess frameworktypedefimplementation_definedvoid_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_tsize,std::size_textra_hdr_bytes);//!Obtains the minimum size needed by the algorithmstaticstd::size_tget_min_size(std::size_textra_hdr_bytes);//!Allocates bytes, returns 0 if there is not more memoryvoid*allocate(std::size_tnbytes);//!Deallocates previously allocated bytesvoiddeallocate(void*adr);//!Returns the size of the memory segmentstd::size_tget_size()const;//!Increases managed memory in extra_size bytes morevoidgrow(std::size_textra_size);/*...*/};
Давайте посмотрим на публичные типдефы, чтобы определить:
<void_pointer>typedef определяет тип указателя, который будет использоваться вBoost.Interprocessфреймворк, использующий алгоритм. Например, если определить
typedefvoid*void_pointer;
ВсеBoost.Interprocessфреймворк, использующий этот алгоритм, будет использовать необработанные указатели в качестве членов. Но если мы определим:
typedefoffset_ptr<void>void_pointer;
Тогда всеBoost.Interprocessframework будет использовать относительные указатели.
<mutex_family>представляет собой структуру, содержащую типдефы для различных типов interprocess_mutex, которые будут использоваться в.Усилить межпроцессныйфреймворк. Например, определенная
Определяет все типы interprocess_mutex с помощью boost::interprocess interprocess_mutex types. Пользователь может указать желаемое семейство mutex.
typedefmutex_familymutex_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, должна быть выровнена с наиболее ограничительным выравниванием памяти системы. Эта функция должна выполняться с возможностями синхронизации, предлагаемыми<typenamemutex_family::mutex_type>interprocess_mutex. Это означает, что если мы определим<typedefmutex_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 algorithmbasic_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 resourcesmanaged_shared_memorysegment(create_only,"/MySharedMemory"//segment name,65536);//segment size in bytes//Obtain the segment managermanaged_shared_memory::segment_manager*segment_mngr=segment.get_segment_manager();//With the segment manager, now we have access to all allocation functionssegment_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 schemeMySTLAllocator<int>stl_alloc(segment_mngr);//Alias a new vector type that uses the custom STL compatible allocatortypedefstd::vector<int,MySTLAllocator<int>>MyVect;//Construct the vector in shared memory with the allocator as constructor parametersegment.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<constkey_type,mapped_type>
Чтобы упорядоченные массивы или деке могли использоваться в качестве типов индексов. Некоторые известные классы, следующие этому базовому интерфейсу, являются<boost::unordered_map>,<boost::interprocess::flat_map>и<boost::interprocess::map>.
Класс должен быть шаблоном класса, принимающим только структуру черт этого типа:
<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 sortingtemplate<...>structindex_key{typedef/*...*/char_type;typedef/*...*/const_char_ptr_t;//Pointer to the object's name (null terminated)const_char_ptr_tmp_str;//Length of the name buffer (null NOT included)std::size_tm_len;//!Constructor of the keyindex_key(constCharT*name,std::size_tlength);//!Less than function for index orderingbooloperator<(constindex_key&right)const;//!Equal to function for index orderingbooloperator==(constindex_key&right)const;};
<mapped_type>непосредственно не изменяется настроенным индексом, но он необходим для определения типа индекса.segment_managerбудет типом менеджера сегмента, который будет управлять индексом.<segment_manager>будет определять интересные внутренние типы, такие как<void_pointer>или<mutex_family>.
Конструктор настроенного типа индекса должен использовать указатель в качестве аргумента конструктора для segment_manager:
constructor(segment_manager*segment_mngr);
Индекс должен обеспечивать функцию резервирования памяти, которая оптимизирует индекс, если пользователь знает количество элементов, подлежащих вставке в индекс:
voidreserve(std::size_tn);
Например, тип индекса<flat_map_index>, основанный на<boost::interprocess::flat_map>, определяется как:
namespaceboost{namespaceinterprocess{#ifndefBOOST_INTERPROCESS_DOXYGEN_INVOKED//!Helper class to define typedefs from IndexTraitstemplate<classMapConfig>structflat_map_index_aux{typedeftypenameMapConfig::key_typekey_type;typedeftypenameMapConfig::mapped_typemapped_type;typedeftypenameMapConfig::segment_manager_basesegment_manager_base;typedefstd::less<key_type>key_less;typedefstd::pair<key_type,mapped_type>value_type;typedefallocator<value_type,segment_manager_base>allocator_type;typedefflat_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<classMapConfig>classflat_map_index//Derive class from flat_map specialization:publicflat_map_index_aux<MapConfig>::index_t{#if!defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)typedefflat_map_index_aux<MapConfig>index_aux;typedeftypenameindex_aux::index_tbase_type;typedeftypenameindex_aux::segment_manager_basesegment_manager_base;#endif//#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKEDpublic://!Constructor. Takes a pointer to the segment manager. Can throwflat_map_index(segment_manager_base*segment_mngr):base_type(typenameindex_aux::key_less(),typenameindex_aux::allocator_type(segment_mngr)){}//!This reserves memory to optimize the insertion of n elements in the indexvoidreserve(typenamesegment_manager_base::size_typen){base_type::reserve(n);}//!This frees all unnecessary memoryvoidshrink_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<classMapConfig>structis_node_index<my_index<MapConfig>>{staticconstboolvalue=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 indextypedefbasic_managed_shared_memory<char,rbtree_best_fit<mutex_family>,my_index_type>my_managed_shared_memory;
Статья Customizing Boost.Interprocess раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 16. Boost.Interprocess может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.