При попытке записать часть (переносимого) кода C ++, который использует shared_memory_segment
для записи в «разделяемую память», я столкнулся с boost::interprocess::bad_alloc
несколько раз.Из Boost документации :
Это исключение выдается, когда запрос памяти не может быть выполнен.
Итак, я должен выделять слишкоммало памяти.Далее следует код (только для записи, поскольку чтение здесь не имеет значения):
shared_memory.h:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <string>
#include <exception>
namespace my_shared_memory
{
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> IPCString;
typedef boost::interprocess::allocator<IPCString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<IPCString, StringAllocator> ShmVector;
bool write_to_memory(std::string wsuid, std::string loop_val, std::string should_intercept, std::string post_data) ;
const std::string shm_prefix = "shm_";
const std::string mutex_prefix = "mtx_";
}
shared_memory.cpp:
#include "shared_memory.h"
namespace apl_shared_memory
{
bool write_to_memory(std::string wsuid, std::string loop_val, std::string should_intercept, std::string post_data)
{
bool ret_val;
std::string shm_name = shm_prefix + wsuid;
std::string mtx_name = mutex_prefix + wsuid;
boost::interprocess::named_mutex named_mtx{boost::interprocess::open_or_create, mtx_name.c_str()};
size_t size = (sizeof(loop_val) + loop_val.size() + sizeof(should_intercept) + should_intercept.size() + sizeof post_data + post_data.size()) * 5;
try
{
named_mtx.lock();
boost::interprocess::shared_memory_object::remove(shm_name.c_str());
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, shm_name.c_str(), size);
CharAllocator charallocator (segment.get_segment_manager());
StringAllocator stringallocator(segment.get_segment_manager());
IPCString shm_loop_val(charallocator);
IPCString shm_should_intercept(charallocator);
IPCString shm_intercepted_data(charallocator);
shm_loop_val = loop_val.c_str();
shm_should_intercept = should_intercept.c_str();
shm_intercepted_data = post_data.c_str();
segment.destroy<ShmVector>("ShmVector");
ShmVector *shmVector = segment.construct<ShmVector>("ShmVector")(stringallocator);
shmVector->clear();
shmVector->push_back(shm_loop_val);
shmVector->push_back(shm_should_intercept);
shmVector->push_back(shm_intercepted_data);
named_mtx.unlock();
ret_val = true;
} catch(const std::exception& ex)
{
ret_val = false;
named_mtx.unlock();
boost::interprocess::shared_memory_object::remove(shm_name.c_str());
}
named_mtx.unlock();
return ret_val;
}
}
Да, я понимаю, мне не нужны unlock
звонки во всех трех местах.
Кажется, проблема в линии:
size_t size = (sizeof(loop_val) + loop_val.size() + sizeof(should_intercept) + should_intercept.size() + sizeof post_data + post_data.size()) * 5;
Я думал, что было бы излишне прибавлять времена 5
, но это, очевидно, не тот случай.Этот код отлично работает на Debian 9 с gcc 6.3.0 и Windows 10 с сообществом Microsoft Visual Studio 2015.Однако на MacOS с Xcode 10.1 я получаю boost::interprocess::bad_alloc
, когда пытаюсь вставить хотя бы первый элемент в вектор.Кажется, что решение умножает размер на 10 вместо 5, но это просто кажется расточительным.
Я добавил segment.get_free_memory
вызовов и определил, что для вектора, который содержит следующие три строки (без кавычек)
"true" "true" ""
Мне нужно 512 байт с Xcode.Оператор sizeof
вернул 32, 24 и 32 для IPCString
, std::string
и ShmVector
соответственно.Поэтому, похоже, мне нужно 32+4
байтов для одной "истинной" строки и 32
для пустой строки.При добавлении ShmVector мне нужно 36+36+32+32=136
байтов для самих структур.Я вычислил размер, используя sizeof(std::string)
, который здесь равен 24 (недосмотр), так что я получаю (28+28+24)*5 = 400
, чего здесь недостаточно.
Мой вопрос здесь состоит в том, как определить, сколько памяти мне нужно для сегмента? Данные, которые я хочу записать в сегмент, известны при вызове функции и, следовательно, имеют размер.
РЕДАКТИРОВАТЬ: Я изменил размер на:
size_t size = (sizeof(IPCString) + loop_val.size() + sizeof(IPCString) + should_intercept.size() + sizeof(IPCString) + post_data.size() + sizeof(ShmVector)) * 2 + 500;
Пока все хорошо.У меня всегда меньше 1060 * байт свободного места после того, как я закончу запись в сегмент.Я пробовал с различными размерами данных, от менее 100 байтов до 3 мегабайт.Я попытался без умножения на 2
, но в этом случае, когда я пытаюсь вставить большие блоки данных, программа вылетает, так как 500
дополнительные байты не обеспечивают достаточную свободу действий.
Если нетответ через пару дней, я выложу эту правку как ответ.