我正在编写一个 C++ 程序,我想要一个有两个进程(使用 fork() 运行)的程序,它们共享一个公共列表,并且有一个进程间互斥体来保护每个进程对共享列表的修改。如何声明列表和互斥体以便它们在进程之间共享。如果需要的话我可以使用 boost 库(如果它让事情变得更容易)
我尝试了 ChatGPT 中的一些内容,但可能是错误的声明,因为出现了重复的列表项
最简单的方法就是分叉后重新打开。这样你就不会冒任何未指定(或未定义)行为的风险。
完整示例:
#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();
}
印刷: