diff --git a/extra/boost_unordered.natvis b/extra/boost_unordered.natvis index ff5e5640..58ba0427 100644 --- a/extra/boost_unordered.natvis +++ b/extra/boost_unordered.natvis @@ -170,7 +170,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - + diff --git a/include/boost/unordered/detail/foa/core.hpp b/include/boost/unordered/detail/foa/core.hpp index db73a866..e89a21cf 100644 --- a/include/boost/unordered/detail/foa/core.hpp +++ b/include/boost/unordered/detail/foa/core.hpp @@ -41,7 +41,7 @@ #include #if defined(BOOST_UNORDERED_ENABLE_STATS) -#include +#include #endif #if !defined(BOOST_UNORDERED_DISABLE_SSE2) diff --git a/include/boost/unordered/detail/cumulative_stats.hpp b/include/boost/unordered/detail/foa/cumulative_stats.hpp similarity index 92% rename from include/boost/unordered/detail/cumulative_stats.hpp rename to include/boost/unordered/detail/foa/cumulative_stats.hpp index 1378c0db..13a15747 100644 --- a/include/boost/unordered/detail/cumulative_stats.hpp +++ b/include/boost/unordered/detail/foa/cumulative_stats.hpp @@ -6,8 +6,8 @@ * See https://www.boost.org/libs/unordered for library home page. */ -#ifndef BOOST_UNORDERED_DETAIL_CUMULATIVE_STATS_HPP -#define BOOST_UNORDERED_DETAIL_CUMULATIVE_STATS_HPP +#ifndef BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP +#define BOOST_UNORDERED_DETAIL_FOA_CUMULATIVE_STATS_HPP #include #include @@ -16,12 +16,14 @@ #include #if defined(BOOST_HAS_THREADS) +#include #include #endif namespace boost{ namespace unordered{ namespace detail{ +namespace foa{ /* Cumulative one-pass calculation of the average, variance and deviation of * running sequences. @@ -117,7 +119,7 @@ template class concurrent_cumulative_stats:cumulative_stats { using super=cumulative_stats; - using lock_guard=std::lock_guard; + using lock_guard=std::lock_guard; public: using summary=typename super::summary; @@ -157,7 +159,7 @@ public: private: concurrent_cumulative_stats(const super& x,lock_guard&&):super{x}{} - mutable std::mutex mut; + mutable rw_spinlock mut; }; #else @@ -167,6 +169,7 @@ using concurrent_cumulative_stats=cumulative_stats; #endif +} /* namespace foa */ } /* namespace detail */ } /* namespace unordered */ } /* namespace boost */ diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index dc2cccca..2b46f4f7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,6 +1,7 @@ # Copyright 2006-2008 Daniel James. # Copyright 2022-2023 Christian Mazakas +# Copyright 2024 Joaquin M Lopez Munoz # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -359,6 +360,27 @@ run cfoa/serialization_tests.cpp /boost//serialization/off : cfoa_serialization_tests ; +rule make_cfoa_interprocess_concurrency_tests ( name : defines ? ) +{ + run cfoa/interprocess_concurrency_tests.cpp /boost/filesystem//boost_filesystem : : + : $(defines) + off + static + clang-3.5:no # Boost.Process does not compile + clang-3.6:no # idem + clang-3.7:no # idem + clang-3.8:no # idem + cygwin:no + : $(name) ; +} + +make_cfoa_interprocess_concurrency_tests cfoa_interproc_conc_tests ; + +make_cfoa_interprocess_concurrency_tests cfoa_interproc_conc_tests_stats + : BOOST_UNORDERED_ENABLE_STATS ; + alias cfoa_tests : cfoa_$(CFOA_TESTS) - cfoa_serialization_tests ; + cfoa_serialization_tests + cfoa_interproc_conc_tests + cfoa_interproc_conc_tests_stats ; diff --git a/test/cfoa/interprocess_concurrency_tests.cpp b/test/cfoa/interprocess_concurrency_tests.cpp new file mode 100644 index 00000000..5cfeea45 --- /dev/null +++ b/test/cfoa/interprocess_concurrency_tests.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2024 Joaquin M Lopez Munoz +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace bip=boost::interprocess; + +static char const* container_name = "shared_map"; +static char const* start_name = "shared_start"; +static constexpr int NUM_OPS_PER_CHILD = 10000; + +using value_type = std::pair; +using allocator = bip::allocator< + value_type, bip::managed_shared_memory::segment_manager>; +using container = boost::concurrent_flat_map< + int, int, boost::hash, std::equal_to, allocator>; + +int parent(const char* exe_name) +{ + static constexpr int NUM_CHILDS = 10; + static constexpr std::size_t SEGMENT_SIZE = 64*1024; + + std::string segment_name_str = to_string(boost::uuids::random_generator()()); + auto* segment_name = segment_name_str.c_str(); + + struct segment_remover + { + char const* name; + + segment_remover(char const* name_) : name(name_) + { + bip::shared_memory_object::remove(name); + } + ~segment_remover() + { + bip::shared_memory_object::remove(name); + } + } remover(segment_name); + + bip::managed_shared_memory segment( + bip::create_only, segment_name, SEGMENT_SIZE); + container& c = *segment.construct(container_name)( + allocator(segment.get_segment_manager())); + std::atomic_int& start = *segment.construct(start_name)(0); + + std::vector children; + for (int i = 0; i < NUM_CHILDS; ++i) { + children.emplace_back(exe_name, std::to_string(i), segment_name); + } + + start.store(1); + + for (auto& child : children) { + child.wait(); + BOOST_TEST_EQ(child.exit_code(), 0); + } + + int num_ops = 0; + c.cvisit_all([&](const value_type& x) { + num_ops += x.second; + }); + BOOST_TEST_EQ(num_ops, NUM_CHILDS * NUM_OPS_PER_CHILD); + + return boost::report_errors(); +} + +int child(int id,const char* segment_name) +{ + bip::managed_shared_memory segment(bip::open_only, segment_name); + container& c = *segment.find(container_name).first; + std::atomic_int& start = *segment.find(start_name).first; + + while(!start.load()){ + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + std::mt19937 rnd((unsigned int) id); + std::geometric_distribution d(0.15); + + for(int i = 0; i < NUM_OPS_PER_CHILD; ++i) { + c.emplace_or_visit(d(rnd), 1, [&](value_type& x) { + ++x.second; + + // artificially increase contention + volatile unsigned int n = 10000; + while(n--) ; + }); + } + return 0; +} + +int main(int argc, char** argv) +{ + if (argc == 1) { + return parent(argv[0]); + } + else { + return child(std::atoi(argv[1]),argv[2]); + } +}