分叉进程之间共享内存c++

问题描述 投票:0回答:1

我正在编写一个 C++ 程序,我想要一个有两个进程(使用 fork() 运行)的程序,它们共享一个公共列表,并且有一个进程间互斥体来保护每个进程对共享列表的修改。如何声明列表和互斥体以便它们在进程之间共享。如果需要的话我可以使用 boost 库(如果它让事情变得更容易)

我尝试了 ChatGPT 中的一些内容,但可能是错误的声明,因为出现了重复的列表项

c++ boost shared-memory
1个回答
0
投票

最简单的方法就是分叉后重新打开。这样你就不会冒任何未指定(或未定义)行为的风险。

完整示例:

住在Coliru

#include <boost/container/map.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/container/string.hpp>
#include <boost/container/vector.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <fmt/ranges.h>
#include <iostream>
#include <thread>
using namespace std::chrono_literals;

namespace Shared {
    namespace bc  = boost::container;
    namespace bip = boost::interprocess;

    using Segment                     = bip::managed_shared_memory;
    using Manager                     = Segment::segment_manager;
    template <typename T> using Alloc = bc::scoped_allocator_adaptor<bip::allocator<T, Manager>>;

    template <typename T> using Vector = bc::vector<T, Alloc<T>>;
    template <typename K, typename V, typename C = std::less<K>>
    using Map    = bc::map<K, V, C, Alloc<std::pair<K const, V>>>;
    using String = bc::basic_string<char, std::char_traits<char>, Alloc<char>>;

    struct MyData {
        using allocator_type = Alloc<MyData>;

        template <typename A> MyData(A&& alloc) : data_(std::forward<A>(alloc)) {}

        size_t count() const {
            for (std::lock_guard lk(mx_);;)
                return data_.size();
        }

        void set(std::string_view key, std::initializer_list<int> values) {
            std::lock_guard lk(mx_);

            if (auto it = data_.find(key); it != data_.end())
                it->second.assign(values.begin(), values.end());
            else
                data_.emplace(key, std::move(values));
        }

        void remove(std::string_view key) {
            std::lock_guard lk(mx_);
            data_.erase(key);
        }

        void print() const {
            std::lock_guard lk(mx_);
            for (auto& [key, values] : data_)
                fmt::print("  {}: {}\n", key, values);
        }

      private:
        mutable bip::interprocess_mutex mx_;

        struct KeyCmp : std::less<std::string_view> { using is_transparent = void; };
        Map<String, Vector<int>, KeyCmp> data_;
    };
} // namespace Shared

static constexpr auto SegmentName = "MySharedMemory";

int parent() {
    using namespace Shared;

    Segment segment(bip::open_only, SegmentName);
    auto [myData, N] = segment.find<MyData>("MyData");
    assert(N == 1); // not an array

    std::this_thread::sleep_for(1s);
    myData->set("foo", {1, 2, 3, 4, 5});
    std::this_thread::sleep_for(1s);
    myData->set("bar", {6, 7, 8, 9, 10});
    std::this_thread::sleep_for(1s);
    myData->set("foo", {5, 4, 3, 2, 1});
    std::this_thread::sleep_for(1s);
    myData->remove("bar");

    std::cout << "parent done" << std::endl;
    return 0;
}

int child() {
    using namespace Shared;

    Segment segment(bip::open_only, SegmentName);
    auto [myData, N] = segment.find<MyData>("MyData");
    assert(N == 1); // not an array

    for (int i : {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) {
        std::this_thread::sleep_for(500ms);
        std::cout << "child foo #" << i << ": " << myData->count() << "\n";
        myData->print();
    }
    std::cout << "child done" << std::endl;
    return 0;
}

int main() {
    {
        using namespace Shared;
        Segment::device_type::remove(SegmentName);
        Segment segment(bip::create_only, SegmentName, 64 << 20ul); // 64MiB
        segment.find_or_construct<MyData>("MyData")(segment.get_segment_manager());
    }
    return fork()? parent() : child();
}

印刷:

© www.soinside.com 2019 - 2024. All rights reserved.