LINUX.ORG.RU

Язык, активно использующий IPC Shared Memory без плясок с бубном?

 , ,


1

4

В заголовке - весь вопрос :)

Мне хотелось бы (как всегда невозможного?):

а) Не использовать файлы в любом виде для передачи данных между процессами

б) Не использовать MQ, in memory NoSQL, ... etc, etc

в) Использовать просто переменные языка, фактически находящиеся в shared memory и защищаемые mutex/semaphor'ами

г) Желательно, чтобы программа на языке «автомагически» умела чистить за собой созданные ею shared memory segment'ы при завершении дерева порождённых ею процессов. Возможно, стоит это делать в рамках cgroup'ы, но это уже досужие домыслы

Но главный вопрос всё-таки в том, умеет ли какой-либо язык программирования безо всяких явных сериализаций/десериализаций хранить в Shared Memory свои переменные?

Заранее сурово признателен! :)

★★★★★

Ответ на: комментарий от kawaii_neko

Ты сейчас описал POSIX shared memory: man shm_open.

к чему было это высказывание? я знаю что такое POSIX shared memory

файл в рамдиске нужен был потому, что в любом яп есть доступ к файлам. Даже в его Java (я не знаю что у ТС-а за любимый ЯП, просто так, для примера сказал).

reprimand ★★★★★
()
Ответ на: комментарий от RazrFalcon

Именно. ТС ищет язык, в котором легко реализуется IPC. То есть беспроблемный доступ к одним и тем же данным из разных потоков/процессов.

Давайте не будем сразу углубляться в детали. ТС ищет решение на нужную ему одному узкоспециализированную задачу БЕЗ (!) плясок с бубном.

Вы же, предлагаете ему язык, в котором эта задача недостижима даже в пределах одного потока.

Это ЛОР а не платная техподдержка. Я показал пример в границах того что умею и в границах ранее описанного сценария.

reprimand ★★★★★
()
Последнее исправление: reprimand (всего исправлений: 1)
Ответ на: комментарий от reprimand

А ТС что, «прогромизд» на Qt?

Это топикстартер: «хочу такую универсальную абстракцию, которая на зашибись решает мою весьма специфичную задачу, но вникать в детали я как-та ниахота».

Для подобных инвалидов, кстати, есть boost::interprocess, но оно сильно на любителя.

kawaii_neko ★★★★
()
Ответ на: комментарий от reprimand

я знаю что такое POSIX shared memory

Интересно было бы услышать твою версию.

файл в рамдиске нужен был потому, что в любом яп есть доступ к файлам

Да я смотрю, ты тот еще затейник: а рутовый доступ для «монтирования рамдиска» тоже есть у каждого?

kawaii_neko ★★★★
()
Ответ на: комментарий от RazrFalcon

Уточню всё же, что не имею ничего против явной защиты критической секции мутексом, чтобы, например, потомки, не забирали структуру, которая находится в процессе обновления и ещё не готова к использованию (не обладает свойством целостности и согласованности).

Единственное требование - чтобы работа с переменными в shared memory отличалась от работы с обычными переменными исключительно наличием кода, предупреждающего коллизии одновременного параллельного доступа.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от kawaii_neko

Да я смотрю, ты тот еще затейник: а рутовый доступ для «монтирования рамдиска» тоже есть у каждого?

Это проблемы деплоя софта, к разработке которого он причастен, но никак не мои

reprimand ★★★★★
()
Последнее исправление: reprimand (всего исправлений: 1)
Ответ на: комментарий от kawaii_neko

Это топикстартер: «хочу такую универсальную абстракцию, которая на зашибись решает мою весьма специфичную задачу, но вникать в детали я как-та ниахота».

Да, я это же и сказал постом выше. Мне просто интересно почему происходит ассоциация с теми, кто использует Qt как разработчик.

reprimand ★★★★★
()
Ответ на: комментарий от kawaii_neko

Ммм. Уточню немного, что меня смущает.

Космические корабли бороздят просторы.

Hadoop уже 10 лет как победно шагает в светлое будущее.

Уже 2 года как пользователям смартфонов перестало хватать 10-ти ядер и примерно столько же языку Rust, который просто обязан забороть всё и всех.

Но... просто обеспечить удобный доступ к разделяемой памяти, самой обычной оперативной памяти, страницы которой мапятся в несколько процессов сразу - почему-то можно только из языков уровня Си. Говорят вот ещё из LISP-подобных языков можно.

Я не против Си и не против LISP'а, но...по-моему это можно было бы реализовать в каждом первом языке программирования, тем более современном языке.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от reprimand

Давайте не будем сразу углубляться в детали. ТС ищет решение на нужную ему одному узкоспециализированную задачу

Неправда вообще ни разу.

Вы храните в памяти исключительно целые числа и простейшие структуры?

А если структура данных сложная, то её никогда не нужно разделять между процессами?

Ну я вам завидую конечно. Но из того, что оно вам лично не нужно - не следует того, что не нужно вообще никому.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

А кто сказал, что в других языка этого нет?

почему-то можно только из языков уровня Си

И даже там так просто нельзя. Что мешает выделять кусок памяти и сериализировать/десериализировать её при необходимости? Накладные расходы минимальны, а в итоге получаем тоже самое, что вам нужно. И это будет работать во всех языках.

Ну и как обычно: если эта «фишка» нигде не реализована, может она никому не нужна или имеет фатальный недостаток?

RazrFalcon ★★★★★
()

О, а это ведь тот же чувак, который не хотел учить алгоритмы. Как характерно.

anonymous
()
Ответ на: комментарий от DRVTiny

Неправда вообще ни разу.

Любая задача сама по себе специфична. Все задачи можно обобщить лишь по отдельным признакам. Собственно, за решение конкретных задач вам платит деньги ваш работодатель.

Вы храните в памяти исключительно целые числа и простейшие структуры? А если структура данных сложная, то её никогда не нужно разделять между процессами?

Я храню в памяти то, что мне нужно. Суть в том, что компьютерная память линейна, хотите вы этого или нет. То, что у вас там «структуры» - это то, как вы воспринимаете/используете эту память.

Ну я вам завидую конечно.

Чему именно?

Но из того, что оно вам лично не нужно - не следует того, что не нужно вообще никому.

Вот тут согласен. Суть была не в нужности или ненужности. См. первую часть этого поста.

reprimand ★★★★★
()
Ответ на: комментарий от reprimand

Подойдёт так:

shared $graph=get_graph_from_rdbm();
my $sem=Some::Semaphore::Package->open('/protect.graph');
$events->on('update'=>sub {
 $sem->wait(sub {
   $graph=get_graph_from_rdbm();
   $sem->unlock();
 });
});
# fork and wait our workers ...
DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

по-моему это можно было бы реализовать в каждом первом языке программирования

Просто взять и реализовать нельзя. Это в Cи структура это кусок памяти с которой можно работать напрямую, а в большинстве языков обычная переменная уже структура со скрытой от пользователя реализацией, и потому подсовывать этому языку кусок памяти и говорить, что там несломанная структура крайне неусмотрительно.

vodz ★★★★★
()
Ответ на: комментарий от reprimand

Я храню в памяти то, что мне нужно. Суть в том, что компьютерная память линейна, хотите вы этого или нет. То, что у вас там «структуры» - это то, как вы воспринимаете/используете эту память.

Спасибо, Капитан! Что бы я без Вас делал?

На Сях тоже есть библиотеки для работы с хешами, всякими динамическими списками какой угодно направленности и массивами. Да и для графов тоже всё есть. Вопрос только в том, насколько трудоёмко всем этим пользоваться, да ещё если оно размещено в shared memory. Если бы Си был идеально удобен для решения любых задач - зачем нужны были бы какие-то иные языки? Однако же, почему-то они есть...

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от vodz

А кто запрещает языку самому управлять куском памяти? Как раз очень хорошо, если к структуре в shm будет доступ только средствами языка, а не произвольный побайтовый как в Си.

Если же shm разрушается как-то со стороны, не их данной программы на языке - это уже не проблема языка. С таким же успехом можно сломать вообще всё, что угодно, включая собственные части тела, и с доступом ко всякого рода расшаренным файлам ситуация ничуть не лучше: например, тот же flock в *nix вообще не mandatory и не может быть таковым: об этом flock любой процесс с подходящим EUID/EGID, не проверяющий блокировки, даже не узнает никогда и смело запишет туда всё, что угодно, делов-то!

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от reprimand

По-моему либо вообще не конкатенировать ничего, либо какая разница, точкой оно конкатенируется или чем-нибудь вроде strconcat(char *buf, char *s1, char *s2) ? Вы так уверены в том, что заказчику принципиален способ конкатенации?

Вот требования по установке программы, в которых указано, что нужно монтировать рамдиск или создавать какие-то пути и давать к ним права доступа - заказчика могут несколько напрячь. То, как с точки зрения синтаксиса языка выглядит конкатенация - ваше личное дело. С точки зрения машинного кода она всё равно будет выглядеть как-нибудь иначе, не говоря уже о том, что доступ к оперативной памяти - крайне дорогая штука (особенно в условиях высокой загрузки контроллера памяти параллельными обращениями от разных ядер процессора) и любых тупых копирований кусков оной памяти из одного места в другое нужно по мере возможности стараться избегать.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

А кто запрещает языку самому управлять куском памяти?

Соседний процесс. Если это не нить того же процесса, то кусок памяти — это просто свалка.

Но и это не важно. Общая память — это не для удобства, им там и не пахнет, это для скорости. Значить... тадам - работайте с ней быстро через библиотеку на Си. А иначе — нонсенс в квадрате.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Соседний процесс. Если это не нить того же процесса, то кусок памяти — это просто свалка.

Почему нить-то??? Форк процесса создаёт полную копию процесса, создавшего структуру в shm. Он что, после форка резко забудет, чего сам же и насоздавал?

А в чём проблема получить доступ к такой структуре из независимого процесса, если тот написан на языке программирования, создавшем структуру и если известен тип хранящейся структуры?

Если у меня shared memory segment имеет с точки зрения IPC идентификатор 1234 и в нём хранится связный список, созданный языком программирования... Clojure, например, - то в чём суть проблемы зная ID сегмента и способ организации данных в нём как угодно с этими данными работать, не забывая о примитивах синхронизации конечно?

Ну, кроме того факта, что размер сегмента ограничен, о чём почему-то все здесь дружно забыли? ;)

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

По-моему либо вообще не конкатенировать ничего, либо какая разница, точкой оно конкатенируется или чем-нибудь вроде strconcat(char *buf, char *s1, char *s2) ? Вы так уверены в том, что заказчику принципиален способ конкатенации?

Вы не поняли смысл моего сообщения. Его смысл был в ответе на ваш вопрос, суть которого состоит в времени разработки и/или неосиляторстве со стороны современных «погромистов».

Вот требования по установке программы, в которых указано...

Давайте не отходить в сторону от реальности, ок?
Современный софт устанавливается либо пакетами либо каким-то другим, автоматизированным способом. В обоих способах есть post-install script, который делает всё что нужно для работы.
Если и требуется вмешательство в процесс установки - то этим занимается support.

То, как с точки зрения синтаксиса языка выглядит конкатенация - ваше личное дело.

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

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

Вау. Тогда вам, возможно, стоит пересмотреть свои взгляды на существующие ЯП, потому что почти все этим и занимаются. Даже плюсы.

reprimand ★★★★★
()
Последнее исправление: reprimand (всего исправлений: 1)
Ответ на: комментарий от vodz

Общая память — это не для удобства, им там и не пахнет

А что, например, в блокировании на запись отдельных кусков открытого (каким-то чудом, после соблюдения миллиона условий) файла - очень много удобства?

По-моему нет ничего удобнее страниц памяти, замапленных в адресное пространство нескольких процессов: разве что чистить надо за собой эти сегменты вовремя, вот и вся беда.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от reprimand

Его смысл был в ответе на ваш вопрос, суть которого состоит в времени разработки и/или неосиляторстве со стороны современных «погромистов».

Есть ещё такое понятие, как «производительность труда».

Некогда мой коллега в «Экспресс Телекоме» зачем-то писал все типично shell-овские скрипты на C. Скорость работы этих скриптов никого не волновала, писал он их не то, чтобы долго, но я бы написал раз в 20 быстрее... В чём профит был?

Для каждой задачи есть наиболее подходящий инструмент. Предложите алготрейдерам писать не на R или python, а на куда более быстром Си - они вас, мягко говоря, не поймут. И зачастую совсем не потому что Си не оСИлили (это весьма неглупые люди, они осилят при необходимости всё, что угодно, была бы в том потребность), а элементарно потому что у них нет времени на виртуозные ковыряния в malloc'ах.

Собственно посмотрите на Rust - вот он похож на Си во многом, но предлагает куда более богатые возможности «из коробки». Я думаю, весьма немало системных программистов рано или поздно свалят и на него в том числе.

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

Почему нить-то??? Форк процесса создаёт полную копию процесса, создавшего структуру в shm. Он что, после форка резко забудет, чего сам же и насоздавал?

Нити как правило идентичны, мутексы в общей памяти, а после fork получается независимая вилка, где блокировки надо делать долго и трудно через sem*

А в чём проблема получить доступ к такой структуре из независимого процесса, если тот написан на языке программирования, создавшем структуру и если известен тип хранящейся структуры?

В специфике, ведь потому и структура, что меняется не только значение, но и другие поля: флаг инициализации, тип, размер под строки, структура списка и т д. Следовательно в языке должна быть поддержка не просто переменных, а атомарное/блокируещее их изменение для расшаренной памяти, что для остальных переменных такое и не требуется.

vodz ★★★★★
()

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

Тоесть как только шаренная память начинает содержать чтото сложнее одной-двух переменных вопросов появляется намного больше чем ответов.

cvv ★★★★★
()
Последнее исправление: cvv (всего исправлений: 1)

elixir, erlang

anonymous
()

Мне кажется, что концепция владения в rust была создана как раз для упрощения доступа к shared memory и предотвращения всяческих факапов при этом.

Но я бы реализовал это на go с использованием RWMutex.

P.S. Тут многие советуют erlang, но не стоит забывать о том, что erlang messaging - это всегда копирование. Хотя использовать ets в эрланге вполне себе выход.

feofan ★★★★★
()
Ответ на: комментарий от vodz

Нити как правило идентичны, мутексы в общей памяти, а после fork получается независимая вилка, где блокировки надо делать долго и трудно через sem*

Не понимаю, что именно есть трудного в sem'афорах-то? По-моему в 1000 раз проще какой-нибудь «резиновой вёрстки дивами», «центрирования блока по вертикали» или подобных высокомудрых вещей. Кстати, на удивление даже в CSS3 всё ещё нельзя толком центрировать дочерний элемент по вертикали относительно родительского элемента. Ну и что? Все центрируют... по уродски как-то, но каждый ребёнок знает, как сделать это.

А тут семафоры. Просто sem->wait (блокирующий или неблокирующий) и sem->post. Где сложность-то?

Да, наборы семафоров от SysV несколько более заморочены и чреваты race condition'ами на этапе их инициализации, но есть же POSIX-семафоры: простые, удобные и незаметные.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от vodz

Следовательно в языке должна быть поддержка не просто переменных, а атомарное/блокируещее их изменение для расшаренной памяти

В языке должна быть просто поддержка размещения переменных в shared memory. Дальше всё абсолютно так же, как и обычно, никаких изменений вообще не нужно делать.

Если программист меняет переменную в shared memory и не создаёт блокировки - это его личная проблема. Если уж так нужно что-то защищать от дурака (мне лично это нафиг не надо и по-моему никому не надо на самом деле, вся эта безопасность - очередная дерьмовая история про палки в колёсах) - ОК, можно создавать шаренные сегменты при старте программы и по завершении оной - чистить их. Например, вообще запускать программу из-под специального «менеджера зачистки», который не позволит чему-либо остаться висеть в памяти после завершения его «подопечных».

Есть конечно разного рода опасения того, что чужой процесс сможет что-то там прочитать из вашего шареного сегмента памяти и прочие подобные страшные вещи могут произойти (злоумышленник что испортит или подделает). Если надо хранить что-то секретное - шифруйте, запускайтесь из-под специального пользователя и давайте права 0600 на сегмент, делайте что угодно, но не создавайте проблемы нормальным вменяемым людям ради своих 0.01% случаев, когда реально нужно что-то усиленно защищать.

Нужно просто предоставить возможность хранить переменные в шареной памяти - а уж там как этим будут пользоваться - вообще не должно волновать разработчиков языка.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

По-моему в 1000 раз проще какой-нибудь «резиновой вёрстки дивами»,

Вы это специально написали, чтобы получить автоматом возражение о сравнении X с пальцем? ;)

злоумышленник

Да какой там злоумышленник. Речь о том, что в язык надо встроить модификаторы, что вот эти переменные надо размещать вон в том куске памяти, а при обращении к ним надо использовать вон тот самафор, но вот к той переменной можно ждать освобождения, а к этой - возвращать новый тип значения: «занято», но это относится к первому и второму форку, а не к третьему и так далее до бесконечности.

vodz ★★★★★
()
Ответ на: комментарий от RazrFalcon

Я о том, что вы предлагаете оптимизировать софт под конкретную ОС (фактически вендорлок предлагаете)

а затем сами же соглашатель с тем, что популярный софт должен быть доступен на всех ОС.

Я не пишу популярный софт и даже не собираюсь.

И наверное популярный софт должен быть под Windows и Android, поскольку если он популярен и он есть под Linux, то по определению доля его установок под Linux составляет в лучшем случае 1%, а значит - зачем тогда вообще делать его кроссплатформенным, ведь можно силы, затраченные на поддержку кроссплатформенности, потратить на дальнейшее увеличение популярности софта и, вполне вероятно, получить добавочную популярность в 10% супротив утраченной 1%-ной.

Узкоспецифичный софт - должен исходить из того, что это платформа/ОС нужна для его установки, а не он должен подходить под все возможные платформы.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Аргументация уровня: мне так хочется - поэтому это правильно.

RazrFalcon ★★★★★
()
Ответ на: комментарий от reprimand

код

Интересно, а если в storage не-pod засунуть, оно будет работать? Ну там, связный список например. Или вообще что угодно с указателями, ссылками, виртуальными таблицами методов и прочим.

d_a ★★★★★
()
Ответ на: комментарий от d_a

а если в storage не-pod засунуть

Не понял. Что такое «не-pod»?

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

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

reprimand ★★★★★
()
Ответ на: комментарий от reprimand

Не понял. Что такое «не-pod»?

https://ru.m.wikipedia.org/wiki/Простая_структура_данных
Например, связный список, где каждый элемент хранит указатели на соседей не-pod. Потому что его нельзя просто скопировать memcpy, так как потом не выправить внутренние ссылки. Pod-структура из примера слишком проста для реальной пользы, а можно ли так пошарить не-pod? И нет, к синхронизации доступа это отношения не имеет.

d_a ★★★★★
()
Ответ на: комментарий от d_a

Для этого я использую не чистые указатели, а смещение относительно некоторого элемента, например в типе size_t

А когда мне нужен сам указатель я делаю ptr + seek. Даже если участок памяти изменит свою адресацию (например, в следствии realloc()), я смогу достучаться до нужного адреса. mmap() сдесь лишь частный случай

reprimand ★★★★★
()
Ответ на: комментарий от reprimand

Для этого я использую не чистые указатели, а смещение относительно некоторого элемента, например в типе size_t

Ну то есть всё свелося к сериализации в pod-структуру получается.

d_a ★★★★★
()

C++ же, ну.

Boost.Interprocess:

Shared memory и Regions

Allocators, containers and memory allocation algorithms - аллокаторы позволят тебе хранить обычные объекты в обычных контейнерах расположенных в шаред мемори.

А подчищать сегменты ты всегда можешь с помощью RAII, как тут

Не очень понимаю, зачем нужны еще какие-то языки проме C++ :)

Deleted
()
Ответ на: комментарий от Deleted

А в чём фундаментальная проблема в языках программирования - почему для работы с shared memory в принципе нужны какие-то обвязки? Чем shared-память принципиально отличается от не-shared - в предположении, что язык не должен вообще ничего знать о том, что это именно shared memory и весь контроль совместного доступа должен лежать на программисте?

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Как раз в С++ все так и есть, как ты пишешь. В языке С++ нет никакой обвязки для шаред мемори. Программист создает удобную абстракцию (а именно, в виде либы Boost.Interprocess) над системной реализацией (lin, win, mac), которая вписывается в существующие принятые в С++ подходы: аллокаторы, пулы, raii, контейнеры, алгоритмы и т.д.

Как это всегда принято в C++ - для программиста всё прозрачно, и весь контроль на нем; но, в отличие от так же прозрачного С, есть более развитые средства для унификации, обобщенного программирования и построения абстраций.

Таков C++, и за это приходится платить некоторой всеобщей громоздкостью, но с которой можно мириться.

А в чём фундаментальная проблема в языках программирования - почему для работы с shared memory в принципе нужны какие-то обвязки?

Фундаментальность, наверное, в следующем. Либо у нас будет по обвязке-костылю в самом языке на каждую фичу, либо у нас будет монстр вида C++, зато с общим подходом. И это не только о шаред мемори.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от d_a

Ну то есть всё свелося к сериализации в pod-структуру получается.

А что ты предлагаешь взамен?

reprimand ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.