我使用boosts进程间库在多个程序之间共享内存。 3或4个其他程序将在cust_order中读取和写入共享内存内容。需要序列化对存储空间的访问。
在下面的示例程序中,引擎循环使用risk_queue的内容,如果已填充,则获取第一个cust_order编号并找到该订单以进行处理。
:
aws cp s3://foo/bar - | wc -l
:
struct cust_order {
int ID;
char CLID[128];
int CUST_ID;
char ORDER_STATUS;
};
cust_order o;
boost::interprocess::managed_shared_memory
cust_order_segment(boost::interprocess::open_or_create, "cust_order",
65536 * 100);
typedef int cust_order_KeyType;
typedef cust_order cust_order_MappedType;
typedef std::pair<const int, cust_order> cust_order_ValueType;
typedef boost::interprocess::allocator<
cust_order_ValueType,
boost::interprocess::managed_shared_memory::segment_manager>
cust_order_ShmemAllocator;
typedef boost::interprocess::map<cust_order_KeyType, cust_order_MappedType,
std::less<cust_order_KeyType>,
cust_order_ShmemAllocator>
cust_order_MySHMMap;
cust_order_MySHMMap::iterator cust_order_iter;
boost::interprocess::managed_shared_memory
risk_queue_segment(boost::interprocess::open_or_create, "risk_queue",
65536 * 100);
typedef int risk_queue_KeyType;
typedef int risk_queue_MappedType;
typedef std::pair<const int, int> risk_queue_ValueType;
typedef boost::interprocess::allocator<
risk_queue_ValueType,
boost::interprocess::managed_shared_memory::segment_manager>
risk_queue_ShmemAllocator;
typedef boost::interprocess::map<risk_queue_KeyType, risk_queue_MappedType,
std::less<risk_queue_KeyType>,
risk_queue_ShmemAllocator>
risk_queue_MySHMMap;
risk_queue_MySHMMap::iterator risk_queue_iter;
这是程序完美运行几秒钟后出现的错误:
int main() {
risk_queue_ShmemAllocator risk_queue_alloc_inst(
risk_queue_segment.get_segment_manager());
cust_order_ShmemAllocator cust_order_alloc_inst(
cust_order_segment.get_segment_manager());
for (; 0 < 1;) {
boost::interprocess::offset_ptr<risk_queue_MySHMMap> risk_queue_m_pmap =
risk_queue_segment.find<risk_queue_MySHMMap>("risk_queue").first;
boost::interprocess::offset_ptr<cust_order_MySHMMap> cust_order_m_pmap =
cust_order_segment.find<cust_order_MySHMMap>("cust_order").first;
risk_queue_iter = risk_queue_m_pmap->begin();
if (risk_queue_iter != risk_queue_m_pmap->end()) {
ordid = risk_queue_iter->second;
cust_order_m_pmap->find(ordid)->second = o;
o.ORDER_STATUS = '0';
o = cust_order_m_pmap->find(ordid)->second;
risk_queue_m_pmap->erase(ordid);
}
};
return 0;
}
请你帮我理解错误。让我知道,如果有更好的方式让我做我需要做的事情。
答案 0 :(得分:1)
但为了使这项工作,我必须在循环中分配内存
我不明白为什么会这样。您的共享内存大小容量限制为64kb(65536字节),因此这是一个明智的选择:预先分配一次。
我的应用程序是低延迟导向的,我想知道是否有办法在内存中读取更新的对象而不必在每次循环迭代中不断重新分配?
是。索引到映射到进程地址空间的共享内存区域,无需分配。
下面是我必须放在循环中的代码,以便从访问相同内存空间的其他程序接收更新。
您展示的代码不会分配任何东西。它在托管段内定位已分配(和构造)的对象。并返回指向它的指针。
如果我把它放在循环之外,当其他程序在共享内存空间中操作或添加数据时,我将不会收到更新
唉唉!您没有告诉我们X_MySHMMap
是什么样的,但我可以开始猜测它可能包含std::array<char, N>
或您循环的其他容器。
如果您对多个进程中的该对象进行取消同步访问,请输入Data Race。编译器有一个内存模型(参见同一页面),它允许它重新排序内存操作并消除加载/存储周期。例如。如果你写
static bool ready = false;
int main() {
while (!ready) {
std::cout << "waiting...\n";
}
}
编译器将此视为有保证的无限循环。想象ready
在共享内存中,编译器根本就没有区别。您必须添加同步(通过使用互斥,互斥+条件变量,原子或在简单的情况下,您可以标记对象volatile
)。
我的猜测是当你在循环中find
对象/再次/每次,你不小心在进程之间进行同步(因为段管理器使用互斥来同步对段元数据的访问),那是什么使编译器发出新的读取。
您没有提供足够的代码来实际为您显示修复程序。我想我可以告诉managed_shared_memory
可能会让事情过于复杂。你可以使用一个简单的shared_memory_object
(它没有段管理器的开销),并且确保让编译器知道你的数据是从另一个“线程”¹中易失/同时访问的。这使它无法优化您需要的负载。
简单示例:
<强> Live On Coliru 2 强>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <array>
#include <atomic>
using SharedBuffer = std::array<std::atomic_char, 65536>;
static_assert(std::is_pod<SharedBuffer>{}, "assumed POD"); // Warning: trait is not correct on some versions of MSVC
namespace bip = boost::interprocess;
int main() {
bip::shared_memory_object smo(bip::open_or_create, "yoho", bip::mode_t::read_write);
smo.truncate(sizeof(SharedBuffer));
bip::mapped_region region(smo, bip::mode_t::read_write, 0, 65536);
auto& buffer = *reinterpret_cast<SharedBuffer*>(region.get_address());
// do something with that buffer
std::fill(buffer.begin(), buffer.end(), 0); // start with all zeroes
// loop over it or something
}
¹(线程在另一个进程中没有区别) ²Coliru不允许共享内存访问