Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать? Или легче все в C-шные массивы загнать?
Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.
А>Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать? Или легче все в C-шные массивы загнать? А>Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.
если "расшарить" означает разместить в памяти, разделяемой между различными процессами, то не стоит использовать STL.
с размещением контейнеров STL в расшаренной памяти имеется следующий проблемы:
1. чтобы они выделяли память для элементов и вспомогательных структур в расшаренной памяти.
2. чтобы они использовали указатели, готовые к тому, что данные будут доступны в разных процессах по разным адресам.
теоретически, обе проблемы решаются через свои аллокаторы, если реализация STL будет всегда учитывать тип указателя, заданный аллокатором, и будет производить все выделения/освобождения через аллокатор. практически, это не работает, по крайней мере для STL идущей с MSVC. "правильные" контейнеры STL можно взять в boost::interprocess, там же есть всё остальное для интерпроцессного расшаривания.
С-шные массивы будут работать, если под ними понимать именно С-шныемассивы, а не С-шные указатели, и std::string тоже заменить на С-шный массив.
если "расшарить" означает разделять между модулями в пределах процесса, то всё проще. проблема может быть с выделением памяти в одном модуле и освобождением в другом, если таких выделений/осовбождений нет, или они происходят на том же хипе, то это будет работать.
Спасибо за ответ. Шарить нужно между процессами. Правильно ли я понял, что при использовании interprocess::map придется использовать бустовскую shared memory? Возможно прикрутить interprocess::map к секции? типа:
On 05.09.2011 23:42, Аноним 415 wrote: > struct SomeDataObject > { > std::map<uint, Settings> data; > }; > > > > Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать?
Почему нет-то ? В чём проблема ?
Или > легче все в C-шные массивы загнать?
Если тебе легче -- загоняй, в чём проблема ?
> Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.
Здравствуйте, tris, Вы писали:
T>Спасибо за ответ. Шарить нужно между процессами. Правильно ли я понял, что при использовании interprocess::map придется использовать бустовскую shared memory? Возможно прикрутить interprocess::map к секции? типа:
так работать не будет по следующим причинам:
1. так будет выделена память на сам экзепляр map, но не на объекты, сохранённые в нём по указателю. т.е. выделится только sizeof(my_map).
2. конструктор объекта будет вызываться для каждого процесса, в который DLL загружается.
При большом желании использовать именно секцию, можно выделить достаточный объём для всех элементов
#pragma section("MySec", read, write, shared)
__declspec(allocate("MySec")) BYTE sharedMemory[100500];
затем определить такой аллокатор, чтобы выделял на этой памяти.
для interprocess::map это реализуемо, но я не могу сходу оценить насколько это сложно и как лучше это сделать.
Здравствуйте, Alexander G, Вы писали:
AG>теоретически, обе проблемы решаются через свои аллокаторы, если реализация STL будет всегда учитывать тип указателя, заданный аллокатором, и будет производить все выделения/освобождения через аллокатор. практически, это не работает, по крайней мере для STL идущей с MSVC.
Я встретил такую "игру не по правилам" в версии STL от MSVC2005 только в классе _Tree реализации дерева, и его методе _Buynode.
Там использовался стандартный placement new вместо конструктора из аллокатора.
Использовался потому, что конструктору объекта требуется 5 аргументов (в конструкторе из аллокатора предусмотрен только один).
А тебя есть другие примеры, где "практически, это не работает" ?
Здравствуйте, rus blood, Вы писали:
RB>Здравствуйте, Alexander G, Вы писали:
AG>>теоретически, обе проблемы решаются через свои аллокаторы, если реализация STL будет всегда учитывать тип указателя, заданный аллокатором, и будет производить все выделения/освобождения через аллокатор. практически, это не работает, по крайней мере для STL идущей с MSVC.
RB>Я встретил такую "игру не по правилам" в версии STL от MSVC2005 только в классе _Tree реализации дерева, и его методе _Buynode. RB>Там использовался стандартный placement new вместо конструктора из аллокатора. RB>Использовался потому, что конструктору объекта требуется 5 аргументов (в конструкторе из аллокатора предусмотрен только один).
в 2008 та же ерунда
RB>А тебя есть другие примеры, где "практически, это не работает" ?
std::list то же не работают из, за
typedef _Node *_Nodeptr; // _Node allocator must have ordinary pointers
в классе _List_nod
кстати, в _Buynode у std::list нет placement new, поэтому я не думаю, что у _Tree это из-за 5-аргументного конструктора.
std::list используется в stdext::hash_map и прочих хеш-контейнерах.
таким образом, оказались сломаны все ассоциативные контейнеры.
этого было достаточно для вывода "практически, это не работает".
Здравствуйте, Alexander G, Вы писали:
AG>в 2008 та же ерунда
RB>>А тебя есть другие примеры, где "практически, это не работает" ?
AG>std::list то же не работают из, за AG> typedef _Node *_Nodeptr; // _Node allocator must have ordinary pointers AG>в классе _List_nod
Это очень странно.
В версии от MSVC2005 нет такого определения _Nodeptr.
Вот начало класса _List_nod:
template<class _Ty,
class _Alloc>
class _List_nod
: public _Container_base
{ // base class for _List_ptr to hold allocator _Alnodprotected:
struct _Node;
friend struct _Node;
typedef typename _Alloc::template
rebind<_GENERIC_BASE>::other::pointer _Genptr;
Тип _Nodeptr не определяется.
Далее определяется класс _List_ptr, и в нем — тип _Nodeptr:
template<class _Ty,
class _Alloc>
class _List_ptr
: public _List_nod<_Ty, _Alloc>
{ // base class for _List_val to hold allocator _Alptrprotected:
typedef typename _List_nod<_Ty, _Alloc>::_Node _Node;
typedef typename _Alloc::template
rebind<_Node>::other::pointer _Nodeptr;
Здравствуйте, rus blood, Вы писали:
RB>Это очень странно. RB>В версии от MSVC2005 нет такого определения _Nodeptr.
посмотрел на 2005 — да, там по-другому, возможно, std::list и stdext::hash_* там совместимы с интерпроцессными аллокаторами.
в любом случае, стандарт не требует от реализации STL всегда учитывать тип указателя в аллокаторе, поэтому в других реализациях STL запросто могут быть такие же проблемы с любыми контейнерами. в boost::interprocess STL-контейнеры были включены именно потому, что обычные STL-контейнеры не поддерживают интерпроцессные аллокаторы.
Здравствуйте, Alexander G, Вы писали:
AG>так работать не будет по следующим причинам: AG>1. так будет выделена память на сам экзепляр map, но не на объекты, сохранённые в нём по указателю. т.е. выделится только sizeof(my_map). AG>2. конструктор объекта будет вызываться для каждого процесса, в который DLL загружается.
AG>При большом желании использовать именно секцию, можно выделить достаточный объём для всех элементов AG>#pragma section("MySec", read, write, shared) AG>__declspec(allocate("MySec")) BYTE sharedMemory[100500];
AG>затем определить такой аллокатор, чтобы выделял на этой памяти. AG>для interprocess::map это реализуемо, но я не могу сходу оценить насколько это сложно и как лучше это сделать.
Поглядел я interprocess и появились вопросы:
1. Мне необходимо, чтобы при первой загрузке Dll выделялась память, создавалась моя map. Или если библиотека уже загружена 1 процессом, то нужно просто открыть расшаренный сегмент и получить указатель на map. Затем один из процессов записывает в map(экспорт. функция dll), а другой — читает (тоже экспорт. ф-я dll). Т.е. хочется, чтобы вся кутерьма с расшаренной памятью ограничивалась dll, но как определить какая по счету эта загрузка dll. Только если сделать тупо счетчик в __declspec(allocate("MySec")) int cnt = 0; но это уже какое-то извращение..2 типа расшаривания в 1 библиотеке
2. Нужно чтобы 2 процесса использовали интерфейсные(экспорт из dll) ф-ии типа:
int set_map(const std::map<uint, Settings> data_to_set);
int get_map(std::map<uint, Settings> data_to_set);
Но использование в dll interprocess::map, vector, string, как я понимаю, автоматом обязывает в этих 2 процессах использовать соответствующие контейнеры. Как-то это печально, заставлять разработчиков 2 приложений привинчивать boost::interprocess.
Здравствуйте, tris, Вы писали:
T>Поглядел я interprocess и появились вопросы: T>1. Мне необходимо, чтобы при первой загрузке Dll выделялась память, создавалась моя map. Или если библиотека уже загружена 1 процессом, то нужно просто открыть расшаренный сегмент и получить указатель на map. Затем один из процессов записывает в map(экспорт. функция dll), а другой — читает (тоже экспорт. ф-я dll). Т.е. хочется, чтобы вся кутерьма с расшаренной памятью ограничивалась dll, но как определить какая по счету эта загрузка dll. Только если сделать тупо счетчик в __declspec(allocate("MySec")) int cnt = 0; но это уже какое-то извращение..2 типа расшаривания в 1 библиотеке
open_or_create с тем же именем сегмента.
T>2. Нужно чтобы 2 процесса использовали интерфейсные(экспорт из dll) ф-ии типа: T>
интерфейс непонятен. map передаётся по значению в обе функции, как что-то достать?
T>Но использование в dll interprocess::map, vector, string, как я понимаю, автоматом обязывает в этих 2 процессах использовать соответствующие контейнеры. Как-то это печально, заставлять разработчиков 2 приложений привинчивать boost::interprocess.
конструктор или метод assign контейнера может принимать пару итераторов. так можно сделать копирование/присваивание между std и interprocess контейнерами.
если предполагается map, лежащий в расшаренной памяти только как временный контейнер, то, пожалуй map в расшаренной памяти — далеко не самое оптимальное решение.
Здравствуйте, Alexander G, Вы писали:
AG>open_or_create с тем же именем сегмента.
Да, я вопрос не так задал. Вот примерно алгоритм, который в dll:
0. Библиотеку кто-то загрузил
1. Делаем managed_shared_memory segment(open_or_create, "MySharedMemory", 65536);
2. Ищем или создаем map segment.find_or_construct<..>("..")(..);
3. Все подготовительная часть закончилась. Идет обмен между процессами.
4. Процессы начинают вырубаться, выгружая dll. Как сделать однократно segment.destroy_ptr(map_ptr) и shared_memory_object::remove("MySharedMemory");? Или повторный вызов не приведет к исключению? Про однократность спрашиваю, потому что, например, весь функционал (пункты 1-4) можно засунуть в конструктор и деструктор оберточного класса.
AG>интерфейс непонятен. map передаётся по значению в обе функции, как что-то достать?
Извиняюсь, имелось в виду:
int set_map(const std::map<uint, Settings> & data_to_set);
int get_map(std::map<uint, Settings> & data_to_get);
AG>конструктор или метод assign контейнера может принимать пару итераторов. так можно сделать копирование/присваивание между std и interprocess контейнерами.
А, понятно..я думал там сложнее
Насчет целесообразности, я согласен. В данный момент для интенсивного обмена данными я использую обычную shared секцию и она меня устраивает. Массивы с-шные. Но понадобилось передавать некую мета-информацию, причем передача фактически однократная. И данная информация представлена в виде объекта, состоящего из stl контейнеров. Вот я и задался вопросом, а как "шарить stl". В итоге решил эту информацию просто в виде xml-файла передавать. А интересуюсь и глупые вопросы задаю про interprocess на будущее, пригодится. Спасибо, что отвечаете