Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.92/25: Рейтинг темы: голосов - 25, средняя оценка - 4.92
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700

Как сохранить данные контейнера в разделяемой памяти

15.02.2017, 11:20. Показов 5643. Ответов 61
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Ищу быстрый способ обмена данными между процессами. Процессы - одинакового типа т.е одна и та же программа и все процессы на одной машине.
Вроде как быстрее чем использование shared memory ничего на ум не приходит

Каким образом можно хранить unordered_map в shared memory так что бы все процессы в связке имели к нему доступ на чтение и запись?
Причем нужно заранее сделать reserve для бакетов хеш таблицы и эти бакеты должны быть зарезервированы в shared memory

От дополнительных рекомендаций по синхронизации (кроме мьютексов) не откажусь
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.02.2017, 11:20
Ответы с готовыми решениями:

Аська на основе разделяемой памяти
Прогреры и хакеры и им подобные... обращаюсь с особой просьбой: есть мысли по поводу перессылки сообщений через разделяемую память между...

Считать структуру из разделяемой памяти
Добрый день! Есть разделяемый файл. В приложении А в файл запихиваю структуру. В приложении Б считываю эту структуру из файла. Выдается...

Синхронизация доступа к разделяемой памяти
Когда потоки являются дочерними по отношению к процессу тут все просто - объект мьютекса находится в общей памяти и используя этот объект...

61
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
17.02.2017, 10:59  [ТС]
Студворк — интернет-сервис помощи студентам
Renji,
Я понял, большое спасибо!
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 17:49  [ТС]
Renji,
Немного запутался, нужна помощь.

Если я буду оперировать индексами в шаред мемори как вы предложили, и учитывая что каждому индексу будет соответствовать структура-список, у которой конечно же есть указатель на следующий элемент, и память для каждого элемента списка будет выделена с помощью кастомного аллокатора из шаред мемори, могу ли я быть уверен что вызов (shared_memory[index]->next).some_var будет выдавать корректные данные во всех процессах несмотря на то, что указатели в процессах будут разными?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 18:18
Цитата Сообщение от sys_beginner Посмотреть сообщение
Если я буду оперировать индексами в шаред мемори как вы предложили, и учитывая что каждому индексу будет соответствовать структура-список
Я сказал "смещение", а не "индекс".
C++
1
2
3
4
5
6
size_t toOffset(const void*baseAddress,const void*address){
    return (char*)address-(char*)baseAddress;
}
void*fromOffset(const void*baseAddress,size_t offset){
    return (char*)baseAddress+offset;
}
Цитата Сообщение от sys_beginner Посмотреть сообщение
могу ли я быть уверен что вызов (shared_memory[index]->next).some_var будет выдавать корректные данные
Да, если -> делается через перегруженный operator-> гоняющий преобразования смещение->адрес по типу приведенных выше.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 18:35  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Да, если -> делается через перегруженный operator-> гоняющий преобразования смещение->адрес по типу приведенных выше.
Не очень понял о чем речь... Покажу псевдокодом что я приблизительно имею ввиду

C++
1
2
3
void *sharedMemory = operator new(size);//это наш большой непрерывный блок. представим что вместо operator new аллоцируем из шаред мемори
HashTable *table = myMallocFromShared(sharedMemory, sizeof(void*) * elements_count);
table[0] = new(myMallocFromShared(sharedMemory, sizeof(ListElement))) ListElement();
Теперь могу ли я из всех процессов действовать так: (table[0]->next) = new(myMallocFromShared(sharedMemory, sizeof(ListElement)))?
И писать/читать таким же макаром в элемент списка?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 19:11
Цитата Сообщение от sys_beginner Посмотреть сообщение
Не очень понял о чем речь...
У меня стойкое ощущение что вам надо изучить устройство памяти. В особенности механизм работы виртуальных адресов.
Речь идет о том, что для доступа к "большому непрерывному блоку", каждый процесс отображает этот блок на свой личный диапазон виртуальных адресов. Именно "свой личный", а не общий для всех процессов. И так как у разных процессов блок лежит по разным адресам, то любой указатель переданный между процессами автоматически превращается в тыкву.
С другой стороны, блок остается непрерывным. А значит смещение от начала блока до, скажем, середины будет во всех процессах одинаковым. Вот это смещение вам и надо хранить вместо указателей.

С другой стороны, вы таки можете попробовать всегда отображать блок по одному и тому же адресу. Одна беда - непонятно как застолбить этот самый адрес за собой. Если у системы уже что-то по нужному адресу лежит, она вас просто пошлет.
Цитата Сообщение от sys_beginner Посмотреть сообщение
Теперь могу ли я из всех процессов действовать так: (table[0]->next) = new(myMallocFromShared(sharedMemory, sizeof(ListElement)))?
Нет. -> пытается раскрыть указатель, а указатель стал тыквой. Но еще раз повторяю, operator-> можно перегрузить чтоб он работал со смещениями, но делал вид что это указатель.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 19:24  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Именно "свой личный", а не общий для всех процессов.
ааа я понял, то есть в моем примере в [0] запишется конкретный адрес и именно его получит другой процесс, а там может лежать что угодно.

что самое интересное в отдельности все понятно, но когда все сливаю в одно целое немного путаюсь, опыта мало

Но блин не соображу если работать только со смещениями то как реализовать эту хеш таблицу
Header*next(){return (Header*)((char*)this+size);} как вы показали в таком случае не катит
потому что этот offset который получится уже может быть занят кем то другим, тем чье смещение было определено именно в этот участок. Либо он будет свободен и мы туда что то запишем но со временем появится индекс который будет подходить под этот участок т.е head + (sizeof(element) * index)
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 19:36
Цитата Сообщение от sys_beginner Посмотреть сообщение
Header*next(){return (Header*)((char*)this+size);} как вы показали в таком случае не катит
потому что этот offset который получится уже может быть занят кем то другим, тем чье смещение было определено именно в этот участок.
Пардон, if(header->size>=size) if(header->size>=size && header->isFree)
Этот код не для хештаблицы. Этот код для учета занятых/незанятых участков.
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 20:04  [ТС]
Renji,
Знаю что скорее всего уже вас задолбал, но очень хочется познать истину ) Похоже я все напутал. Постараюсь заново описать суть задачи и пояснить что именно мне не понятно.

Задача: Нужно создать хеш таблицу данные которой будут доступны между процессами.
Нужные операции:
1. Чтение
2. Запись

В качестве общего хранилища у нас есть шаред мемори. На указатели мы не можем полагаться. Только на смещения.
Допустим мы выделили большой непрерывный кусок памяти как вы предложили. Ок отлично, память у нас тоже есть

Теперь пришло время записать значение в хеш таблицу по ключу.
1. Отработала хеш функция для данных ключа
2. Из результата хеш функции получили параметр для определения смещения методом index = hash % elements_size
3. Смещение будет следующим: heap_head + sizeof(element) * index
До сих пор все понятно.

Теперь раз уж все что у нас есть это смещение и с указателями работать нельзя, что делать если индекс повторился?
Как я понял вы предлагаете занять следующий кусок памяти за текущим смещением если он свободен.
А если не свободен, прыгать на следующее смещение и так пока не найдется свободное смещение.
Предположим мы нашли такое смещение и оно равно heap_head + (sizeof(element) * 5)
Затем появился новый элемент, индекс которого стал равным 5, но в смещение где индекс равен 5 мы писать не можем т.к next прежде описанного элемента его занял. Что делать? Ок можно искать дальше свободное место и записать новые данные туда когда оно найдется. НО, с какого смещения читать такой индекс если заранее неизвестно в каком смещении в памяти его данные будут зафиксированы?
Я вижу в таком случае один вариант чтения: хранить исходный индекс внутри элемента списка и при каждом поиске линейно ходить по большому куску памяти что бы найти нужное соответствие но тогда нафиг нужна такая хеш таблица, смысла нету.

Вот мои мысли... может я ошибаюсь, поправьте если это так
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 20:17
Цитата Сообщение от sys_beginner Посмотреть сообщение
Теперь раз уж все что у нас есть это смещение и с указателями работать нельзя, что делать если индекс повторился?
Так понятней?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
char heap[1<<20];
void*baseAddress=heap;
template<typename T>
class OffsetPointer
{
public:
    OffsetPointer&operator=(T*value){
        offset=(char*)value-(char*)baseAddress;
        return*this;
    }
    T&operator*(){return*(T*)((char*)baseAddress+offset);}
    T*operator->(){return (T*)((char*)baseAddress+offset);}
private:
    size_t offset;
};
 
struct test
{
    OffsetPointer<test> next;
};
 
int main()
{
    OffsetPointer<test> myPointer;
    myPointer=(test*)heap;
    myPointer->next=myPointer;
    return 0;
}
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 20:39  [ТС]
Цитата Сообщение от Renji Посмотреть сообщение
Так понятней?
Как идея имитации указателя хорошая, спасибо. Но я в упор не вижу что с этим делать что бы решить те вопросы которые расположены после той цитаты которую вы привели печатая этот пост
0
22 / 22 / 7
Регистрация: 01.02.2017
Сообщений: 54
Записей в блоге: 1
19.02.2017, 20:42
У меня в Wind'е работает обмен между процессорами посредством динамически подключаемой библиотеки, где память выделяется так:
C++
1
2
3
4
5
6
        g_hFile = CreateFileMapping((HANDLE) 0xffffffff,    // не файл на диске
                                    NULL,                   // без системы безопасности
                                    PAGE_READWRITE,         // чтение и запись
                                    0,                      // нет в Win32
                                    si.dwPageSize,          // размер блока
                                    _T("TBridgeFile"));     // имя файла
Отобразить выделенную память (сделать её доступной) в библиотеке нужно так:
C++
1
2
3
        g_pcd = (CCommunicationData*) MapViewOfFile(g_hFile,
                                                    FILE_MAP_ALL_ACCESS,
                                                    0, 0, 0);
Таким образом, эту память можно использовать в разных процессах по указателю без проблем. Экспортируй из своей библиотеки (dll) указтаель g_pcd, в импортирующем процессе приводи её к любым объектам и индексируй как хочешь...

В других операционках наверняка подобный подход реализован. Т.к. смысл "разделяемой памяти" как раз и заключается в том, что память доступна в разных процессах по идентичным в разных процессах адресам.
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 20:58
Цитата Сообщение от sys_beginner Посмотреть сообщение
Как идея имитации указателя хорошая, спасибо. Но я в упор не вижу что с этим делать что бы решить те вопросы которые расположены после той цитаты которую вы привели печатая этот пост
1) Написать хеш-таблицу на Си и без шаред-мемори.
2) Заменить все malloc на myMalloc выделяющий память из шаред-мемори.
3) Заменить указатели на OffsetPointer.
Если у вас возникают затруднения с пунктом один, то лучше ни в какие шаред-мемори не лезть.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 21:07  [ТС]
Цитата Сообщение от svetogor Посмотреть сообщение
Т.к. смысл "разделяемой памяти" как раз и заключается в том, что память доступна в разных процессах по идентичным в разных процессах адресам.
Это как так? У каждого процесса свои адреса даже при работе с шаред мемори

Renji,
Я попробую, спасибо
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 21:16
Цитата Сообщение от svetogor Посмотреть сообщение
Т.к. смысл "разделяемой памяти" как раз и заключается в том, что память доступна в разных процессах по идентичным в разных процессах адресам.
Только если вы используете MapViewOfFileEx и задали этот адрес последним аргументом. Однако "While it is possible to specify an address that is safe now (not used by the operating system), there is no guarantee that the address will remain safe over time. Therefore, it is better to let the operating system choose the address. In this case, you would not store pointers in the memory mapped file, you would store offsets from the base of the file mapping so that the mapping can be used at any address."
0
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
19.02.2017, 23:28  [ТС]
Renji,
Кажется я понял суть реализации.

1. Выделяем большой кусок памяти из шаред мемори
2. Например в хеш таблице нужно хранить 5 элементов, выделяем для таблицы с помощью MyAlloc из большого куска размер sizeof(element) * 5 и пишем туда свои данные когда это нужно.
3. Каждый элемент списка содержит в себе псевдоуказатель на следующий элемент. Этот псевдоуказатель ориентируется на смещения
4. Когда возникает коллизия, c помощью MyAlloc ищем для next свободный блок в большом куске шаред мемори, а когда находим присваиваем найденное смещение next-у и помечаем блок как занятый и после этого можем класть туда свои данные
5. Так как псевдоуказатель запомнил свое смещение в поле offset, при следующим обращении мы можем быстренько прыгнуть на ту позицию которая была для него выделена и работать с данными
6. Если выделенной большой памяти не хватило, аллоцируем блок еще большим размером, копируем туда прежде занесенные данные и избавляемся от предыдущего блока

Я верно понял реализацию?
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
19.02.2017, 23:50
Цитата Сообщение от sys_beginner Посмотреть сообщение
Я верно понял реализацию?
Да, все верно.
1
901 / 478 / 93
Регистрация: 10.06.2014
Сообщений: 2,700
20.02.2017, 00:41  [ТС]
Renji,
Большое спасибо!
Вы очень помогли!
0
22 / 22 / 7
Регистрация: 01.02.2017
Сообщений: 54
Записей в блоге: 1
22.02.2017, 12:29
Цитата Сообщение от sys_beginner Посмотреть сообщение
Это как так? У каждого процесса свои адреса даже при работе с шаред мемори
Операционка-то контролирует всю память в целом. Вышеприведённый вариант у меня работает, начиная с Win-98. С переходом на Win-XP пришлось подправить первоначальный вариант, но не в плане применения Win-API.

"Линейщикъ - обмен данными между процессами" в трубе:
.

Не проверял в Win-10, в остальных окнах работает нормально.

Добавлено через 19 минут
Только если вы используете...
Да, microsoft'ы рекомендуют отображать разделяемую память в каждом процессе ф-цией MapViewOfFile(Ex) по дескриптору от Create/OpenFileMapping, и использовать её как файл, отступая от начала. Я рассматриваю разделяемую память как конкретный адрес, в каждый процесс подключаю библиотеку, где только однажды отображаю память, оттуда экспортирую указатель и объекты синхроназации. Этот указатель вполне нормально эксплуатируется в разных потоках отдельных процессов: https://youtu.be/TziEeC6gZas
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
22.02.2017, 13:35
Цитата Сообщение от svetogor Посмотреть сообщение
Я рассматриваю разделяемую память как конкретный адрес, в каждый процесс подключаю библиотеку
...У которой от этого подключения повторно срабатывает DLL_PROCESS_ATTACH ветка DLLMain и заново выполняются все процедуры инициализации.
Цитата Сообщение от svetogor Посмотреть сообщение
Этот указатель вполне нормально эксплуатируется в разных потоках отдельных процессов
Для взаимодействия потоков разделяемая память не используется. Она используется для взаимодействия процессов, в каждом из которых отработает свой экземпляр DLLMain, со своей копией "глобальных" переменных. Разумеется, локальная копия указателя в данном процессе, после выполнения локальной же инициализации, будет содержать корректное значение.
PS Извините, но лекции на Ютубе не смотрю принципиально. Есть что сказать - говорите буквами.
1
22 / 22 / 7
Регистрация: 01.02.2017
Сообщений: 54
Записей в блоге: 1
22.02.2017, 20:16
Для взаимодействия потоков разделяемая память не используется.
Память используется по усмотрению программера. Как он захочет, так и использует память. У меня память используется для обмена данными между процессами и между потоками экземпляров (instances) моего приложения.
PS Извините, но лекции на Ютубе не смотрю принципиально. Есть что сказать - говорите буквами.
Но мою-то посмотрели, зачем лукавить-то... Потому что
Цитата Сообщение от Renji Посмотреть сообщение
Она используется для взаимодействия процессов, в каждом из которых отработает свой экземпляр DLLMain, со своей копией "глобальных" переменных.
слово "глобальных" вы именно там и прочитали.

Но переменные действительно глобальные, доступные в процессах, подгружающих библиотеку. Потому что кроме функций, библиотека может экспортировать данные как базовых типов, так и составных - объекты классов, например, со всеми их атрибутами и методами.
повторно срабатывает DLL_PROCESS_ATTACH ветка DLLMain и заново выполняются все процедуры инициализации
На то она и точка входа, чтобы выполняться. Никто ведь не заставляет делать одну и ту же работу повторно. Один раз выполнили "ветку" и хватит.
Книжек вы вдоволь начитались, теперь самое время попрактиковаться. И у вас тоже всё получится.
Миниатюры
Как сохранить данные контейнера в разделяемой памяти  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.02.2017, 20:16

Запись и считывание разделяемой памяти
Всем доброго времени суток. Столкнулся с одной проблемой. Есть две программы: 1 создаёт разделяемую память и записывает туда данные, а...

Хранение указателей в разделяемой памяти
Выручайте ребята. Задали лабораторную на взаимодействие процессов. Не могу справиться с сохранением указателей на структуры в...

Сделать массив из 10 int в разделяемой памяти
Хочу сделать массив из 10 int в разделяемой памяти. Доступ из разных процессов от fork(). Так понимаю, 19-20 строки должны сказать...

В чем основное преимущество разделяемой памяти
Подскажите в чем основное преимуществоразделяемой памяти

Прогон программ с использованием разделяемой памяти
/* Мы организуем разделяемую память для массива из трех целых чисел. Первый элемент массива является счетчиком числа запусков программы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Многофункциональное здание: как одно здание порождает конфликты требований, которые никто не планировал (мат мет мод 29)
anaschu 23.06.2026
Многофункциональное здание: как одно здание порождает конфликты требований, которые никто не планировал Материалы для обсуждения с МГСУ · 2026 Рисунки внутри приложенного ворд файла. Что за. . .
28. Конкретное развертывание плана номер 1 из поста номер 27
anaschu 22.06.2026
Можно ли из модели получить конкретные строительные требования? Честно — напрямую из текущей модели такие ответы не получить. Но цепочка логики есть, и она не такая длинная. Где разрыв . . .
27. Планы на разработку функциональных требований к строительству внутри модели пищеблока (или не только его?)
anaschu 22.06.2026
Что уже реализовано и даёт конфликты «бесплатно» Самый простой конфликт уже работает — конфликт за ресурс-работника. Заданий больше, чем доступных поваров → очередь в queue1. Это прямое отражение. . .
26. мед мат модель.Какие типы конфликтов функциональных требований можно рассчитать через ДЕС-моделирование (СМО) в AnyLogic?
anaschu 22.06.2026
Что ДЕС/ СМО умеет считать напрямую: Конфликты за ресурсы (очереди, узкие места). Несколько типов агентов (повара, учителя, рабочие, пациенты) претендуют на один ресурс (лифт, вход, коридор,. . .
25 модель здравосохранения и функциональных требований к пищеблоку: конфликты функциональных требований.
anaschu 22.06.2026
Есть ли данные о том, какие функциональные/ эксплуатационные требования или их сочетания труднее всего учитывать при проектировании зданий? Да, такие данные есть, и они хорошо описаны и в российской,. . .
Remote Connection Manager
DevAlt 21.06.2026
Написал для себя небольшую прилагу: https:/ / github. com/ altbodhi/ ReConMan По итогу пришел к мысли, что DU не дружат с существующими технологиями. От сериализации до отображения в реляционную. . .
Администрация Хабра удаляет новые энрегоэфективные алгоритмы, которые не западной школы кода, и вовсе никак не сгенерировавны.
Hrethgir 20.06.2026
Делается это, как замечено, при правках - при объявлении концептуальных отличий в алгоримах. Делается это, по линейке событий - после дополнения публикации основными отличиями от основных западных. . .
Процесс ориентированная диалектика (не новость - просто системное обновление, философия).
Hrethgir 20.06.2026
Однажды один участник в своём блоге, на этом форуме, сделал запись "О языках замолвите слово". Понимая, что язык - важная вещь, я решил хорошо подумать, прежде чем сказать, и сказал то, что вы видите. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru