Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/56: Рейтинг темы: голосов - 56, средняя оценка - 4.95
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
1

Синхронизация доступа к разделяемой памяти

21.02.2017, 12:08. Показов 10183. Ответов 73
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Когда потоки являются дочерними по отношению к процессу тут все просто - объект мьютекса находится в общей памяти и используя этот объект можно делать mutex.lock() определенной секции а при завершении работы mutex.unlock();

А как синхронизировать доступ к данным shared memory между процессами?
Подозреваю что в таком случае мьютекс нужно хранить разделяемой памяти
Но как конкретно это реализуется плохо представляю
Подскажите пожалуйста кто знает
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.02.2017, 12:08
Ответы с готовыми решениями:

Реализация стека строк в разделяемой памяти (MPI)
Написать реализацию стека строк в разделяемой памяти. При запуске программа создает блок...

Как сохранить данные контейнера в разделяемой памяти
Ищу быстрый способ обмена данными между процессами. Процессы - одинакового типа т.е одна и та же...

Есть ли оверхед от использования разделяемой памяти, в сравнении с глобальной?
Если оверхед есть, то по каким причинам? Я понимаю что зависит от реализации. Но если есть какие...

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

73
7793 / 6560 / 2984
Регистрация: 14.04.2014
Сообщений: 28,672
21.02.2017, 12:24 2
Если речь о Windows, то CreateMutex()/OpenMutex() смотри. И здесь: https://msdn.microsoft.com/en-... s.85).aspx
2
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 12:48  [ТС] 3
nmcf,
Желательно кросплатформенное решение.
Но в первую очередь интересуют linux-based операционки

Добавлено через 18 минут
Вот тут есть описание похожее на правду
http://stackoverflow.com/quest... nxos-posix
Надо проверить
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
21.02.2017, 12:54 4
Цитата Сообщение от sys_beginner Посмотреть сообщение
Желательно кросплатформенное решение.
Собирать спинлок на std::atomic_flag. Однако же "The C++ standard recommends (but does not require) that lock-free atomic operations are also address-free, that is, suitable for communication between processes using shared memory. ". Так что если реализация сделана не по здравому смыслу, а по стандарту, можно получить сюрприз.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 13:43  [ТС] 5
Renji,
Если не ошибаюсь реализовать спинлок можно через CAS используя ассемблерные вставки
Но не знаю каково будет поведение для шаред мемори
Пока думаю так: где-то в шаред куске держать флаг который обновлять CAS-ом
За вариант спасибо, учту

Как я понял если атомик вернул false для is_lock_free - только в этом случае нужно задействовать спинлок?
И атомику нужно отдать объект созданный в шаред мемори? Верно?

Добавлено через 4 минуты
С другой стороны насколько я понимаю теоретически возможна ситуация когда какой-то процесс просто никогда не получит доступ к данным из за наличия спинлока. Или нет?
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.02.2017, 14:03 6
Цитата Сообщение от sys_beginner Посмотреть сообщение
Но в первую очередь интересуют linux-based операционки
Под линуксом есть две сущности - семафор и мьютекс. Принципиальное отличие между ними в том, что мьютексы используются в условиях, когда есть какая-то память, которая видна напрямую из всех потоков исполнения, а семафоры - в условиях, когда общей памяти как бы нет. Ну и по сути это означает, что мьютексы используются для синхронизации thread'ов, а семафоры - для синхронизации process'ов. Технически мьютекс является по сути обычной переменной (т.е. куском памяти в пространстве памяти, общим для потоков), семафор на моей памяти является объектом ядра, косвенно находящимся в файловой системе (т.к. в общем случае у двух процессов нет других общих ресурсов)

Добавлено через 2 минуты
См. sem_open, sem_getvalue, sem_post, sem_wait и прочие интерфейсы по работе с семафорами
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 14:06  [ТС] 7
Цитата Сообщение от Evg Посмотреть сообщение
а семафоры - в условиях, когда общей памяти как бы нет
А на чем тогда основывается синхронизация? На файле? верно?
Цитата Сообщение от Evg Посмотреть сообщение
Технически мьютекс является по сути обычной переменной (т.е. куском памяти в пространстве памяти, общим для потоков)
В таком случае можно ли создать мьютекс в начале разделяемой памяти и лочить/анлочить весь кусок который идет после данных мьютекса? То есть по идее получим ту же ситуацию что и с потоками ведь мьютекс будет сидеть в разделяемой памяти.
Просто не хочется велосипедить если уже есть готовое решение которое можно адаптировать для работы с shared memory (готовое всмысле из коробки языка)
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.02.2017, 14:18 8
Цитата Сообщение от sys_beginner Посмотреть сообщение
А на чем тогда основывается синхронизация? На файле? верно?
На файловой системе (возможно, просто на имени файла) основывается только создание семафора. Сам он в любом случае будет в памяти. Возможно, что под это дело автоматически создаётся страница разделяемой памяти, а может быть в памяти ядра. Я точно не знаю

Цитата Сообщение от sys_beginner Посмотреть сообщение
В таком случае можно ли создать мьютекс в начале разделяемой памяти и лочить/анлочить весь кусок который идет после данных мьютекса?
В теории можно, но тонкостей работы я с ходу не знаю

Цитата Сообщение от sys_beginner Посмотреть сообщение
если уже есть готовое решение которое можно адаптировать для работы с shared memory (готовое всмысле из коробки языка)
Если речь идёт об std::atomic - то это всего лишь переменная с атомарным доступом. Сама по себе она не является средством синхронизации. Такая операция имеет инструменты, при помощи которых создаются мьютексы или им подобные вещи. Т.е. построение мьютекса на таком объекте в любом случае будет велосипедлм (если только для этого нет специальных классов)
1
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
21.02.2017, 14:28 9
Цитата Сообщение от sys_beginner Посмотреть сообщение
Как я понял если атомик вернул false для is_lock_free - только в этом случае нужно задействовать спинлок?
atomic_flag всегда lock-free.
Цитата Сообщение от sys_beginner Посмотреть сообщение
С другой стороны насколько я понимаю теоретически возможна ситуация когда какой-то процесс просто никогда не получит доступ к данным из за наличия спинлока.
Ну, если один из процессов захватил спинлок и повис, то да, больше никто к этому спинлоку доступа не получит. Дальше велосипедим прерывание цикла спинлока по таймеру. Но с таким уровнем велосипедостроения, проще наваять класс GlobalMutex, внутрь него всунуть батарею #ifdef проверяющую текущую ОС (смотреть макросы тут) и подсовывающую платформозависимую реализацию.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 14:44  [ТС] 10
Цитата Сообщение от Evg Посмотреть сообщение
Если речь идёт об std::atomic - то это всего лишь переменная с атомарным доступом. Сама по себе она не является средством синхронизации.
Почему же? От части вроде является. Как я понимаю атомиком можно сделать различные данные и доступ к ним из потоков будет синхронным. Но там есть еще вспомогательные методы которые были бы полезны для реализации мьютекса-велосипеда

Добавлено через 57 секунд
Цитата Сообщение от Renji Посмотреть сообщение
внутрь него всунуть батарею
как это батарею? термин не ясен ))
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.02.2017, 15:02 11
Цитата Сообщение от sys_beginner Посмотреть сообщение
Как я понимаю атомиком можно сделать различные данные и доступ к ним из потоков будет синхронным
Не синхронным, а атомарным. В атомарном доступе нет никаких концепций типа "освободить ресурс", "занять ресурс" и т.п. Все эти концепции - только на уровне программных соглашений в голове программиста
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 15:05  [ТС] 12
Цитата Сообщение от Evg Посмотреть сообщение
Не синхронным, а атомарным.
ну в любом случае насколько я понимаю одновременного доступа не будет

Renji, Evg,
Хотел создать atomic в шаред мемори и изменять этот флаг через вызов compare_exchange_weak но обломался, нет конструктора для оператора присваивания

Как то так пытался... может можно иным способом, которого я не знаю, уложить его в шаред мемори?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <atomic>
 
int main()
{
    void *sharedMemory = operator new(sizeof(std::atomic<bool>));//предположим что это смещение для атомика в шаред мемори
    
    std::atomic<bool> atomic = new(sharedMemory)std::atomic<bool>(true);
    
    bool flag = true;
    atomic.compare_exchange_weak(flag, false);
    
    std::cout << atomic.load();
}
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.02.2017, 15:12 13
Цитата Сообщение от sys_beginner Посмотреть сообщение
ну в любом случае насколько я понимаю одновременного доступа не будет
Условно не будет. Но смысл мьютексов и семафоров вовсе не в этом
0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 15:15  [ТС] 14
Блин можно, я ступил. Вот так надо (в прежнем примере забыл принимающую переменную сделать указателем)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <atomic>
 
int main()
{
    void *sharedMemory = operator new(sizeof(std::atomic<bool>));//предположим что это смещение для атомика в шаред мемори
    
    std::atomic<bool> *atomic = new(sharedMemory)std::atomic<bool>(true);
    
    bool flag = true;
    atomic->compare_exchange_weak(flag, false);
    
    std::cout << atomic->load();
}
Добавлено через 37 секунд
Могу ли я на это полагаться? то бишь обновлять атомарно флаг в шаред мемори и полагаться на его значение занято/не занято при работе с данными в разделяемой памяти?

Добавлено через 38 секунд
Цитата Сообщение от Evg Посмотреть сообщение
Условно не будет.
А почему условно?
Цитата Сообщение от Evg Посмотреть сообщение
Но смысл мьютексов и семафоров вовсе не в этом
А в чем? Они же вопросы синхронизации решают когда конечная цель - решить проблемы конкурентного доступа
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
21.02.2017, 15:17 15
Цитата Сообщение от sys_beginner Посмотреть сообщение
как это батарею? термин не ясен ))
C++
1
2
3
4
5
6
7
8
9
10
11
12
#ifdef _WIN32
class GlobalMutex
{
реализация мутекса под винду
};
#endif
#ifdef __linux__
class GlobalMutex
{
реализация мутекса под Линукс
};
#endif
Конкретные ключи в ifdef скорее всего будут привязаны к компилятору.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 15:19  [ТС] 16
Renji,
Ясно спасибо.
А что скажете насчет примера с атомиком в шаред мемори который я написал выше?
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
21.02.2017, 15:26 17
Цитата Сообщение от sys_beginner Посмотреть сообщение
А что скажете насчет примера с атомиком в шаред мемори который я написал выше?
Что надо использовать atomic_flag потому что "Unlike all specializations of std::atomic, it is guaranteed to be lock-free".
Собственно, тут вот уже готовый мютекс на atomic_flag лежит.
1
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
21.02.2017, 15:36  [ТС] 18
Renji,
Правильно ли я понял как это юзать?
C++
1
2
3
4
void *sharedMemory = operator new(1024);
std::atomic_flag_test_and_set_explicit(sharedMemory , std::memory_order_acquire);//захватить доступ к блоку шаред мемори
//работаем
std::atomic_flag_test_and_set_explicit(sharedMemory , std::memory_order_release);//освободить доступ к блоку шаред мемори
0
2782 / 1935 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
21.02.2017, 15:39 19
Цитата Сообщение от sys_beginner Посмотреть сообщение
Правильно ли я понял как это юзать?
Флаг надо сначала ATOMIC_FLAG_INIT инициализировать. И освобождается он через std::atomic_flag_clear_explicit. Ну и пример если вы пропустили:
C++
1
2
3
4
5
6
7
8
9
10
11
std::atomic_flag lock = ATOMIC_FLAG_INIT;
 
void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while(std::atomic_flag_test_and_set_explicit(&lock, std::memory_order_acquire))
             ; // spin until the lock is acquired
        std::cout << "Output from thread " << n << '\n';
        std::atomic_flag_clear_explicit(&lock, std::memory_order_release);
    }
}
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
21.02.2017, 15:58 20
Цитата Сообщение от sys_beginner Посмотреть сообщение
А почему условно?
Потому что технически доступ может быть одновременный, но аппаратура это разрулит. В общем, не бери в голову

Цитата Сообщение от sys_beginner Посмотреть сообщение
А в чем?
Мьютексы должны предоставлять интерфейсы вида "занять ресурс", "освободить ресурс и т.п.". Атомарные операции используются для реализации этих интерфейсов, но тождественно им не равны. Т.е. для реализации интерфейсов в общем случае нужно использовать атомарные операции плюс дополнительный обвес. Т.е. мьютекс - это более высокоуровневая конструкция, чем атомарныя операция

Добавлено через 10 минут
Цитата Сообщение от Renji Посмотреть сообщение
C++
1
2
while(std::atomic_flag_test_and_set_explicit(&lock, std::memory_order_acquire))
    ; // spin until the lock is acquired
Что делать, если ресурс занят, вообще говоря, зависит от конкретной софтины. Если программист знает, что критическая секция короткая (по времени), то действительно можно пожужжать в цикле. Но если критическая секция длинная (например, обработка файла), то нужно спать. В противном случае будет ситуация, когда 10 потоков ломятся в один ресурс, с ресурсом работает только один поток, а остальные 9 не делают ничего полезного, но нагружают процессор

Добавлено через 3 минуты
Кстати, это одна из причин, почему мьютекс, реализованный с поддержкой ОС, будет более эффективным. В нём можно усыпить процесс, а разбудит его ОС, когда ресурс освободится. Если в очереди будет 10 потоков, то ОС разбудит только один. А в велосипедных реализациях будут километры кода по усыплению, периодическому просыпанию, проверке занятости и повторному засыпанию. Зато будет всё "красиво" с использованием встроенного библиотечного класса std::atomic
1
21.02.2017, 15:58
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
21.02.2017, 15:58
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru