std::multiset functionality support in boost interprocess headers

Hi all, I see multiset is not present in boost interprocess, so I tried to use a "set" with a customized comparator to achieve multiset functionality. sample code: struct set_comparator { bool operator()(const int& a, const int& b) const { return a < b; // if change a <= b then seeing an errror } }; bip::shared_memory_object::remove("SHM"); bip::managed_shared_memory segment(bip::open_or_create, "SHM", 2047*1024*1024); typedef bip::allocator<int, bip::managed_shared_memory::segment_manager> ShmemAllocator; typedef bip::set<int, set_comparator, ShmemAllocator> ShmemSet; segment.destroy<ShmemSet>("MySet"); ShmemSet *sample1 = segment.construct<ShmemSet>("MySet")(set_comparator(), segment.get_segment_manager()); std::cout << "Insert in shared set:" << std::endl; sample1->insert(40); std::cout << "Insert in shared set:" << std::endl; sample1->insert(40); // Crashing here sample1->insert(40); sample1->insert(40); sample1->insert(20); sample1->insert(20); sample1->insert(20); sample1->insert(20); sample1->insert(20); when i try duplicate insertion, seeing following error, /usr/include/boost/intrusive/bstree.hpp:1331: boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::iterator boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::insert_unique_commit(boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::reference, const insert_commit_data&) [with ValueTraits = boost::intrusive::bhtraits<boost::container::dtl::tree_node<int, boost::interprocess::offset_ptr<void>, boost::container::red_black_tree, true>, boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void>, true>, boost::intrusive::normal_link, boost::intrusive::dft_tag, 3>; VoidOrKeyOfValue = void; VoidOrKeyComp = boost::container::value_to_node_compare<boost::container::dtl::tree_node<int, boost::interprocess::offset_ptr<void>, boost::container::red_black_tree, true>, boost::intrusive::tree_value_compare<boost::interprocess::offset_ptr<int, long int, long unsigned int, 0>, main()::set_comparator, boost::move_detail::identity<int>, bool, true>, bool>; SizeType = long unsigned int; bool ConstantTimeSize = true; boost::intrusive::algo_types AlgoType = boost::intrusive::RbTreeAlgorithms; HeaderHolder = void; boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::iterator = boost::intrusive::tree_iterator<boost::intrusive::bhtraits<boost::container::dtl::tree_node<int, boost::interprocess::offset_ptr<void>, boost::container::red_black_tree, true>, boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void>, true>, boost::intrusive::normal_link, boost::intrusive::dft_tag, 3>, false>; boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::reference = boost::container::dtl::tree_node<int, boost::interprocess::offset_ptr<void>, boost::container::red_black_tree, true>&; boost::intrusive::bstree_impl<ValueTraits, VoidOrKeyOfValue, VoidOrKeyComp, SizeType, ConstantTimeSize, AlgoType, HeaderHolder>::insert_commit_data = boost::intrusive::insert_commit_data_t<boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void>
, long int, long unsigned int, 0> >]: Assertion `( p == this->end() || !this->comp()(*p, value) )' failed.
"Need input on this or is this expected behaviour as per boost??" -- Regards, Murali Kishore

El 09/09/2024 a las 15:18, Murali Kishore via Boost escribió:
Hi all,
I see multiset is not present in boost interprocess, so I tried to use a "set" with a customized comparator to achieve multiset functionality.
You can use any Boost.Container container with Boost.Interprocess, including multiset. Boost.Interprocess own container aliases will be deprecated soon, since they only forward to Boost.Container. I'll maintain those container header inside Interprocess for backwards compatibility for several Boost releases but in the end they will be removed. Best, Ion

Thanks Ion. I have tried the following sample, I see one issue that "find" is failing in the following sample. #include <boost/interprocess/managed_shared_memory.hpp> #include <boost/unordered_map.hpp> #include <boost/interprocess/containers/set.hpp> #include <boost/interprocess/containers/map.hpp> #include <boost/interprocess/containers/vector.hpp> #include <boost/interprocess/containers/string.hpp> #include <boost/interprocess/allocators/allocator.hpp> #include <iostream> // Define your types using timer_id_t = int; struct timer_instance_t { int id; // Example member }; // Define allocators for shared memory typedef boost::interprocess::allocator<timer_instance_t, boost::interprocess::managed_shared_memory::segment_manager> TimerAllocator; typedef boost::interprocess::allocator<std::pair<const timer_id_t, timer_instance_t>, boost::interprocess::managed_shared_memory::segment_manager> MapAllocator; // Define the unordered_map type typedef boost::unordered_map<timer_id_t, timer_instance_t, std::hash<timer_id_t>, std::less<timer_id_t>, MapAllocator> timer_instance_map_t; int main() { using namespace boost::interprocess; // Create managed shared memory managed_shared_memory segment(open_or_create, "MySharedMemory", 65536); // Construct the unordered map in shared memory timer_instance_map_t* timer_instance_map = segment.find_or_construct<timer_instance_map_t>("TimerInstanceMap")(10, std::hash<timer_id_t>(), std::less<timer_id_t>(), segment.get_segment_manager()); // Allocate a timer_instance_t in shared memory timer_instance_t* instance = segment.construct<timer_instance_t>("TimerInstance")(); // Use emplace to insert the timer_instance_t pointer into the map timer_id_t id = 100; timer_instance_map->emplace(id, *instance); // Copy the allocated instance into the map // Accessing the instance auto it = timer_instance_map->find(id); if (it != timer_instance_map->end()) { std::cout << "Found timer instance with id: " << it->second.id << std::endl; } else { std::cout << "Timer instance not found." << std::endl; } for (const auto& pair : *timer_instance_map) { std::cout <<"Timer Id: " << pair.first <<", Timer Instance Id: " << pair.second.id<< std::endl; } // Cleanup: You may want to remove the shared memory segment shared_memory_object::remove("MySharedMemory"); return 0; } output: Timer Instance not found. Timer Id: 100, Timer Instance Id: 0 need help in understanding why find is failing. Regards, Murali Kishore On Mon, Sep 9, 2024 at 8:42 PM Ion Gaztañaga <igaztanaga@gmail.com> wrote:
El 09/09/2024 a las 15:18, Murali Kishore via Boost escribió:
Hi all,
I see multiset is not present in boost interprocess, so I tried to use a "set" with a customized comparator to achieve multiset functionality.
You can use any Boost.Container container with Boost.Interprocess, including multiset.
Boost.Interprocess own container aliases will be deprecated soon, since they only forward to Boost.Container. I'll maintain those container header inside Interprocess for backwards compatibility for several Boost releases but in the end they will be removed.
Best,
Ion
-- Regards, Murali Kishore

El 28/09/2024 a las 9:49, Murali Kishore via Boost escribió:
[...]
// Define the unordered_map type typedef boost::unordered_map<timer_id_t, timer_instance_t, std::hash<timer_id_t>, std::less<timer_id_t>, MapAllocator> timer_instance_map_t;
You have to use std::equal_to<timer_id_t> rather than std::less<timer_id_t>. Please try and let us know if that solves your issue. Joaquin M Lopez Munoz

Thanks, it worked. On Sat, Sep 28, 2024 at 2:36 PM Joaquin M López Muñoz via Boost < boost@lists.boost.org> wrote:
El 28/09/2024 a las 9:49, Murali Kishore via Boost escribió:
[...]
// Define the unordered_map type typedef boost::unordered_map<timer_id_t, timer_instance_t, std::hash<timer_id_t>, std::less<timer_id_t>, MapAllocator> timer_instance_map_t;
You have to use std::equal_to<timer_id_t> rather than std::less<timer_id_t>. Please try and let us know if that solves your issue.
Joaquin M Lopez Munoz
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Regards, Murali Kishore

Hi, I am observing that the first 4 bytes are changed to zero, let me know what is the reason for this. before insert: (gdb) p instance $1 = (ngp::timer_manager::timer_instance_t &) @0x7fffb610e118: {padding = *1919*, id = 2, api_id = 1, next = {__d = { __r = 98595033760891}}, period = {__r = 20000}, max_iterations = -1, running = false, user_data = 0x0, target_identifier = 0, startAddr = 0x5555555c22cb <boost::interprocess::ipcdetail::CtorArgN<ngp::timer_manager::timer_instance, false, int, unsigned long&, unsigned long&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, std::chrono::duration<long, std::ratio<1l, 1000l> >, int&, void*&, unsigned int&>::construct<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul>(void*, boost::interprocess::ipcdetail::bool_<false>, boost::container::dtl::index_tuple<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul> const&)+401>, startTime = 177880440076688, interval = 20000} *after insert (queue->insert(instance))* (gdb) p instance $4 = (ngp::timer_manager::timer_instance_t &) @0x7fffb610e118: {*padding = 0*, id = 2, api_id = 1, next = {__d = { __r = 98595033760891}}, period = {__r = 20000}, max_iterations = -1, running = false, user_data = 0x0, target_identifier = 0, startAddr = 0x5555555c22cb <boost::interprocess::ipcdetail::CtorArgN<ngp::timer_manager::timer_instance, false, int, unsigned long&, unsigned long&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > >, std::chrono::duration<long, std::ratio<1l, 1000l> >, int&, void*&, unsigned int&>::construct<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul>(void*, boost::interprocess::ipcdetail::bool_<false>, boost::container::dtl::index_tuple<0ul, 1ul, 2ul, 3ul, 4ul, 5ul, 6ul, 7ul> const&)+401>, startTime = 177880440076688, interval = 20000} here queue is typedef bip::multiset<timer_instance_t, timer_comparator, ShmemAllocator_Timer> timer_queue_t; timer_queue_t* queue; typedef struct alignas(4) timer_instance { uint32_t padding; timer_id_t id; uint64_t api_id; timestamp_t next; millis_t period; int32_t max_iterations; // handler_type_t handler; bool running; void* user_data; uint32_t target_identifier; void* startAddr; uint64_t startTime; uint64_t interval; } Regards, Murali Kishore On Sat, Sep 28, 2024 at 3:17 PM Murali Kishore <bmuralikishore@gmail.com> wrote:
Thanks, it worked.
On Sat, Sep 28, 2024 at 2:36 PM Joaquin M López Muñoz via Boost < boost@lists.boost.org> wrote:
El 28/09/2024 a las 9:49, Murali Kishore via Boost escribió:
[...]
// Define the unordered_map type typedef boost::unordered_map<timer_id_t, timer_instance_t, std::hash<timer_id_t>, std::less<timer_id_t>, MapAllocator> timer_instance_map_t;
You have to use std::equal_to<timer_id_t> rather than std::less<timer_id_t>. Please try and let us know if that solves your issue.
Joaquin M Lopez Munoz
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Regards, Murali Kishore
-- Regards, Murali Kishore

El 30/09/2024 a las 18:44, Murali Kishore via Boost escribió:
Hi,
I am observing that the first 4 bytes are changed to zero, let me know what is the reason for this.
You need to provide us with a fully compilable example, otherwise it's not easy to deduce what's happenning in your code. Apart from that, you are storing raw pointers inside timer_instance_t, and that is not going to work between processes. See: https://www.boost.org/doc/libs/1_86_0/doc/html/interprocess/sharedmemorybetw... Best, Ion

You still leak instances, because you do a redundant `construct<>` call before emplacing. Always simplify: [Live On Coliru](https://coliru.stacked-crooked.com/a/4d1a689fc03f3910) ```c++ #include <boost/interprocess/allocators/allocator.hpp> #include <boost/interprocess/managed_mapped_file.hpp> // FOR COLIRU #include <boost/interprocess/managed_shared_memory.hpp> #include <boost/unordered_map.hpp> #include <iostream> namespace bip = boost::interprocess; // Define your types using Id = int; struct Timer { int id; }; // Define allocators for shared memory // using Segment = bip::managed_shared_memory; using Segment = bip::managed_mapped_file; // FOR COLIRU template <typename T> using Allocator = bip::allocator<T, Segment::segment_manager>; template <typename K, typename V, typename H = std::hash<K>, typename Eq = std::equal_to<K>> using Map = boost::unordered_map<K, V, H, Eq, Allocator<std::pair<K const, V>>>; using Timers = Map<Id, Timer>; int main() { // Create managed shared memory Segment segment(bip::open_or_create, "MySharedMemory", 65536); // Construct the unordered map in shared memory Timers* timers = segment.find_or_construct<Timers>("TimerInstanceMap") // (10, segment.get_segment_manager()); timers->emplace(100, Timer{100}); timers->emplace(200, Timer{200}); // Accessing the instance for (Id id : {100, 150, 200}) if (auto it = timers->find(id); it != timers->end()) std::cout << "Found timer instance with id: " << it->second.id << std::endl; else std::cout << "Timer instance not found." << std::endl; for (auto const& pair : *timers) std::cout << "Timer Id: " << pair.first << ", Timer Instance Id: " << pair.second.id << std::endl; // Cleanup: You may want to remove the shared memory segment std::remove("MySharedMemory"); // FOR COLIRU // Segment::remove("MySharedMemory"); } ``` On Sat, Sep 28, 2024, at 11:47 AM, Murali Kishore via Boost wrote:
Thanks, it worked.
On Sat, Sep 28, 2024 at 2:36 PM Joaquin M López Muñoz via Boost < boost@lists.boost.org> wrote:
El 28/09/2024 a las 9:49, Murali Kishore via Boost escribió:
[...]
// Define the unordered_map type typedef boost::unordered_map<timer_id_t, timer_instance_t, std::hash<timer_id_t>, std::less<timer_id_t>, MapAllocator> timer_instance_map_t;
You have to use std::equal_to<timer_id_t> rather than std::less<timer_id_t>. Please try and let us know if that solves your issue.
Joaquin M Lopez Munoz
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Regards, Murali Kishore
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (4)
-
Ion Gaztañaga
-
Joaquin M López Muñoz
-
Murali Kishore
-
Seth