shared dll && stl
От: Аноним  
Дата: 05.09.11 19:42
Оценка:
Есть вот такой объект:

struct Settings
{
   uint a;
   uint b;
   uint c;
   std::vector<std::string> strs;
};

struct SomeDataObject
{
   std::map<uint, Settings> data;
};


Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать? Или легче все в C-шные массивы загнать?
Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.
Re: shared dll && stl
От: Alexander G Украина  
Дата: 05.09.11 21:22
Оценка: 6 (2)
Здравствуйте, Аноним, Вы писали:

А>Есть вот такой объект:


А>
А>struct Settings
А>{
А>   uint a;
А>   uint b;
А>   uint c;
А>   std::vector<std::string> strs;
А>};

А>struct SomeDataObject
А>{
А>   std::map<uint, Settings> data;
А>};
А>


А>Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать? Или легче все в C-шные массивы загнать?

А>Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.

если "расшарить" означает разместить в памяти, разделяемой между различными процессами, то не стоит использовать STL.
с размещением контейнеров STL в расшаренной памяти имеется следующий проблемы:
1. чтобы они выделяли память для элементов и вспомогательных структур в расшаренной памяти.
2. чтобы они использовали указатели, готовые к тому, что данные будут доступны в разных процессах по разным адресам.

теоретически, обе проблемы решаются через свои аллокаторы, если реализация STL будет всегда учитывать тип указателя, заданный аллокатором, и будет производить все выделения/освобождения через аллокатор. практически, это не работает, по крайней мере для STL идущей с MSVC. "правильные" контейнеры STL можно взять в boost::interprocess, там же есть всё остальное для интерпроцессного расшаривания.

С-шные массивы будут работать, если под ними понимать именно С-шныемассивы, а не С-шные указатели, и std::string тоже заменить на С-шный массив.

если "расшарить" означает разделять между модулями в пределах процесса, то всё проще. проблема может быть с выделением памяти в одном модуле и освобождением в другом, если таких выделений/осовбождений нет, или они происходят на том же хипе, то это будет работать.
Русский военный корабль идёт ко дну!
Re[2]: shared dll && stl
От: tris  
Дата: 06.09.11 05:46
Оценка:
Спасибо за ответ. Шарить нужно между процессами. Правильно ли я понял, что при использовании interprocess::map придется использовать бустовскую shared memory? Возможно прикрутить interprocess::map к секции? типа:


#pragma section("MySec", read, write, shared)
__declspec(allocate("MySec")) interprocess::map my_map;
Re: shared dll && stl
От: MasterZiv СССР  
Дата: 06.09.11 09:57
Оценка: :)
On 05.09.2011 23:42, Аноним 415 wrote:
> struct SomeDataObject
> {
> std::map<uint, Settings> data;
> };
>
>
>
> Нужно в dll расшарить SomeDataObject. Стоит ли вообще тут stl использовать?

Почему нет-то ? В чём проблема ?

Или
> легче все в C-шные массивы загнать?

Если тебе легче -- загоняй, в чём проблема ?

> Почитал про проблемы stl+dll..как-то печально стало, а тут еще и shared.


Какие проблемы ? В MSVC ?
Posted via RSDN NNTP Server 2.1 beta
Re[3]: shared dll && stl
От: Alexander G Украина  
Дата: 06.09.11 11:24
Оценка:
Здравствуйте, tris, Вы писали:

T>Спасибо за ответ. Шарить нужно между процессами. Правильно ли я понял, что при использовании interprocess::map придется использовать бустовскую shared memory? Возможно прикрутить interprocess::map к секции? типа:



T>
T>#pragma section("MySec", read, write, shared)
T>__declspec(allocate("MySec")) interprocess::map my_map;
T>


так работать не будет по следующим причинам:
1. так будет выделена память на сам экзепляр map, но не на объекты, сохранённые в нём по указателю. т.е. выделится только sizeof(my_map).
2. конструктор объекта будет вызываться для каждого процесса, в который DLL загружается.

При большом желании использовать именно секцию, можно выделить достаточный объём для всех элементов
#pragma section("MySec", read, write, shared)
__declspec(allocate("MySec")) BYTE sharedMemory[100500];

затем определить такой аллокатор, чтобы выделял на этой памяти.
для interprocess::map это реализуемо, но я не могу сходу оценить насколько это сложно и как лучше это сделать.
Русский военный корабль идёт ко дну!
Re[2]: shared dll && stl
От: rus blood Россия  
Дата: 06.09.11 11:52
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>теоретически, обе проблемы решаются через свои аллокаторы, если реализация STL будет всегда учитывать тип указателя, заданный аллокатором, и будет производить все выделения/освобождения через аллокатор. практически, это не работает, по крайней мере для STL идущей с MSVC.



Я встретил такую "игру не по правилам" в версии STL от MSVC2005 только в классе _Tree реализации дерева, и его методе _Buynode.
Там использовался стандартный placement new вместо конструктора из аллокатора.
Использовался потому, что конструктору объекта требуется 5 аргументов (в конструкторе из аллокатора предусмотрен только один).

А тебя есть другие примеры, где "практически, это не работает" ?
Имею скафандр — готов путешествовать!
Re[2]: shared dll && stl
От: tris  
Дата: 06.09.11 13:47
Оценка:
Здравствуйте, MasterZiv, Вы писали:

Сформулирую так: "у меня проблема из-за незнания". Я так понимаю, задача простая и тривиальная. Выше мне люди разъяснили за что им спасибо.
Re[3]: shared dll && stl
От: Alexander G Украина  
Дата: 07.09.11 06:58
Оценка:
Здравствуйте, 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 и прочих хеш-контейнерах.

таким образом, оказались сломаны все ассоциативные контейнеры.
этого было достаточно для вывода "практически, это не работает".
Русский военный корабль идёт ко дну!
Re[4]: shared dll && stl
От: rus blood Россия  
Дата: 07.09.11 10:19
Оценка:
Здравствуйте, 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 _Alnod
protected:
    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 _Alptr
protected:
    typedef typename _List_nod<_Ty, _Alloc>::_Node _Node;
    typedef typename _Alloc::template
        rebind<_Node>::other::pointer _Nodeptr;


Вот сам класс list
template<class _Ty,
    class _Ax = allocator<_Ty> >
    class list
        : public _List_val<_Ty, _Ax>
    {    // bidirectional linked list
public:
    typedef list<_Ty, _Ax> _Myt;
    typedef _List_val<_Ty, _Ax> _Mybase;
    typedef typename _Mybase::_Alty _Alloc;

protected:
    typedef typename _List_nod<_Ty, _Ax>::_Genptr _Genptr;
    typedef typename _List_nod<_Ty, _Ax>::_Node _Node;
    typedef _POINTER_X(_Node, _Alloc) _Nodeptr;
    typedef _REFERENCE_X(_Nodeptr, _Alloc) _Nodepref;
    typedef typename _Alloc::reference _Vref;

Макросы POINTER_X и REFERENCE_X определяются так
#define _POINTER_X(T, A)    \
    typename A::template rebind<T>::other::pointer
 #define _REFERENCE_X(T, A)    \
    typename A::template rebind<T>::other::reference


И никаких _Node*
Имею скафандр — готов путешествовать!
Re[5]: shared dll && stl
От: Alexander G Украина  
Дата: 07.09.11 21:09
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Это очень странно.

RB>В версии от MSVC2005 нет такого определения _Nodeptr.

посмотрел на 2005 — да, там по-другому, возможно, std::list и stdext::hash_* там совместимы с интерпроцессными аллокаторами.
в любом случае, стандарт не требует от реализации STL всегда учитывать тип указателя в аллокаторе, поэтому в других реализациях STL запросто могут быть такие же проблемы с любыми контейнерами. в boost::interprocess STL-контейнеры были включены именно потому, что обычные STL-контейнеры не поддерживают интерпроцессные аллокаторы.
Русский военный корабль идёт ко дну!
Re[4]: shared dll && stl
От: tris  
Дата: 08.09.11 11:00
Оценка:
Здравствуйте, 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.
Re[5]: shared dll && stl
От: Alexander G Украина  
Дата: 08.09.11 12:42
Оценка:
Здравствуйте, 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>
T>int set_map(const std::map<uint, Settings> data_to_set);
T>int get_map(std::map<uint, Settings> data_to_set);
T>

интерфейс непонятен. map передаётся по значению в обе функции, как что-то достать?

T>Но использование в dll interprocess::map, vector, string, как я понимаю, автоматом обязывает в этих 2 процессах использовать соответствующие контейнеры. Как-то это печально, заставлять разработчиков 2 приложений привинчивать boost::interprocess.


конструктор или метод assign контейнера может принимать пару итераторов. так можно сделать копирование/присваивание между std и interprocess контейнерами.

если предполагается map, лежащий в расшаренной памяти только как временный контейнер, то, пожалуй map в расшаренной памяти — далеко не самое оптимальное решение.
Русский военный корабль идёт ко дну!
Re[6]: shared dll && stl
От: tris  
Дата: 08.09.11 18:25
Оценка:
Здравствуйте, 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 на будущее, пригодится. Спасибо, что отвечаете
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.