это единственное решение, которое нагуглилось
других способов сделать именованный мьютекс, видимо, в линуксе нет.
Для начала надо убрать из условия навязанное решение, и ответить на вопрос - как в linux оптимальнее решить задачу «разграничить доступ к общему ресурсу»
не очень понимаю, о чём вы.
избегание одновременного доступа к ресурсу - это как раз то, для чего придуманы мьютексы и семафоры (с семафорами в линуксе та же проблема - нельзя открыть семафор по его имени)
любой обходной путь будет длиннее, чем тупо зафигачить мьютекс
хочу послушать ваш вариант, как в linux оптимальнее решить задачу «избежать одновременного доступа нескольких процессов к общему ресурсу»?
я пишу программу, в которой есть некоторая функция f(), которая иногда вызывается.
требование: если я запустил несколько экземпляров своей программы параллельно, то функция f() должна выполняться одновременно не более чем в одном процессе, остальные процессы должны ждать.
поэтому я на входе в функцию захватываю мьютекс, а на выходе отпускаю.
если вы намекаете, что вместо мьютекса можно создать специальный файл и открывать его в exclusive mode и держать открытым на время выполнения функции, то я знаю этот обходной путь, и это полный треш.
почитал про семафоры
не, не подходит
если во время выполнения функции f() кто-то прибьёт процесс, то зависнет вся система (другие процессы никогда не дождутся этого ресурса)
мьютексы автоматически освобождаются ОСью при убиении процесса, а семафоры нет
Ну то есть, утверждение что семафор нельзя открыть по имени - это дезинформация )))
А вообще тут можно как минимум - 1) проверять читая /proc/self/maps смаплен ли семафор куда-либо или он просто повис после прибиения процесса, 2) Лочить файл 3) Использовать сокет.
В чем «полный треш» подхода лочить файл - я не понимаю.
утверждение что семафор нельзя открыть по имени - это дезинформация
да, не разобрался (видел, что семафорные функции требуют указатель на семафорный объект, и решил, что и тут объект должен быть одним и тем же, а оказалось два разных объекта могут означать один и тот же семафор)
В чем «полный треш» подхода лочить файл - я не понимаю.
зачем добавлять зависимость от файловой системы и иметь головную боль с проверками на существование файла и его права доступа?
проверять читая /proc/self/maps смаплен ли семафор куда-либо или он просто повис после прибиения процесса
и такая проверка будет надёжной?
я вижу, что ничего лучше «жопы с гландами» вы тоже предложить не смогли
«жопа с гландами» хоть и потребует простыню кода на 2 экрана, но она выполнит свою работу
а с сокетом что делать? открывать на прослушку? а если его придётся открывать и закрывать 10000 раз в секунду, он не навредит общей производительности? а где гарантия, что этот сокет не отдадут для входящего TCP-соединения, это же вопрос времени когда такое случится? что-то сомневаюсь я насчёт сокета
насчёт семафора вопрос
ну вот допустим, что выяснилось, что семафор повис по причине смерти процесса.
что дальше-то?
у нас несколько процессов, ожидающих этот семафор, и все хотят «вылечить» ситуацию, вызвав sem_post. но они не могут сделать это одновременно, это должен сделать только кто-то один. а как выбрать этого одного? получаем рекурсию: для реализации корректной работы первого семафора нам нужен ещё один семафор, который бы решал вопрос одновременого доступа к функции «лечения» первого семафора. ну, и у второго семафора будут возможны аналогичные проблемы, и для его лечения потребуется третий, ну вы поняли…
мы снова возвращаемся к вопросу «где выдают пистолет для линуксоидов?»
мы снова возвращаемся к вопросу «где выдают пистолет для линуксоидов?»
Нигде, потому что «жопа с гландами» уж точно решит проблему. И ее единственный недостаток - много вызовов, ну можно это все в библиотечную функцию завернуть, что наверняка по сути и сделано в винде. То есть недостаток перед виндой - то что в ней есть библиотечная функция, внутри делающая много действий, а в POSIX нет такого, эти много действий надо вручную проворачивать. Ну нет а надо - так сделай.
зачем добавлять зависимость от файловой системы и иметь головную боль с проверками на существование файла и его права доступа?
По-моему это не сложно организовать.
Семафоры да, для этой задачи не совсем то.
Меня заинтересовало тут другое - а почему так получилось, что в Винде - есть а в Unix системах нет? Явно неспроста. Потому что очевидно, что «жопу с гландами» можно было давно ввернуть в API в виде отдельной функции.
ну можно это все в библиотечную функцию завернуть, что наверняка по сути и сделано в винде.
нет! ))))
мьютекс - это легковесный (требующий мало телодвижений) способ синхронизации, и реализовывать его через более громоздкое и более мощное средство синхронизации (мапирование памяти между процессами) - это извращение, реализованное только в линуксе
в ту же тему пойдёт и линуксовый fork(): боже, какой же это идиотизм - создавать новый процесс через дублирование старого )))
всё-таки пистолетики линуксоидам надо бы раздать, мы же в гуманном обществе или где? )))
а почему так получилось, что в Винде - есть а в Unix системах нет?
винда задума более логично, интерфейсы сначала хорошо продумывались, и только потом делались (про баги в реализации промолчу)
а линукс создан кучей гиков «о! нет фичи! я сейчас допишу! ну и что, что задизайнено кое-как и другому человеку будет трудно разобраться, эта ось для гиков, пусть попотеет и потом тоже гордится, что пробрался сквозь дебри костылей и примкнул к избранным!»
Мьютекс легковесный - конечно. В линуксе. В винде - это средство IPC. Весьма тяжеловесное.
откуда такой пафос? )))
разница всего в два раза
да, возможно, у линукса переключение в ядро выполняется вдвое быстрее. и что?
а двадцатикратная разница в этом бенчмарке - между мьютексом и крит.секцией
но если ты заглянешь в доку винды, что такое критическая секция, ты увидишь:
Critical section objects cannot be shared across processes.
короче, критическая секция - это менее функциональная хрень, мне она бесполезна
а мьютекс по сути (в ядре) можно написать двумя экранами ассемблерного кода, суть очень проста )))
то видно что линуксовый std::mutex чуть быстрее виндового std::mutex (который через критическую секцию). А Win32 Mutex медленнее в 20 раз. Получается что линуксовый mutex быстрее Win32 более чем в 20 раз. Что легко объяснимо - он между процессами не работает, как и критическая секция в винде.
Теперь - если сравнить «жопу с гландами» и Win32 mutex - наверняка окажется что они и реализованы схожим образом, и работают примерно одинаково по скорости. Потому что чудес не бывает - по-другому синхронизацию между процессами не сделаешь, и если в винде это все завернули в одну красивую функцию - это не значит что эта функция стала легковесной.
Потому что чудес не бывает - по-другому синхронизацию между процессами не сделаешь
конечно сделаешь
нафуя мьютексу мапирование памяти между процессами???
во-первых, мапирование памяти - это долго (поэтому виндовый мьютекс будет намного быстрее, если захватывать мьютекс нужно 1 раз за всю программу, а не миллион раз в цикле)
во-вторых, это нафиг не нужно.
мьютекс в винде - это не объект в памяти юзер-процесса (как в линуксе)
мьютекс в винде - это хэндл объекта, расположенного в ядре (грубо говоря, это индекс в массиве мьютексов, лежащем в памяти ядра)
маппинг памяти между процессами не нужен
кстати, использование хэндлов вместо указателей на объекты - отличная демонстрация продуманности архитектуры винапи по сравнению с линуксячьей архитектурной помойкой
Вы, по ходу, в гуманитарном обществе беспросветной дремучести. Хотя бы чуть-чуть матчасть можно было изучить, прежде чем писать.
Линуксячий — это clone(), а fork(), vfork(), exec() — это POSIX, и там же с 1999 года есть posix_spawn().
fork() это не идиотизм, а удобство, он позволяет часть задач по подготовки окружения дочернего процесса (переменные среды, открытые файлы, маскировка сигналов и т.д.) легко перенести из родительского процесса в дочерний — разгрузить родительский процесс.
это идиотизм
как я понимаю, fork - это единственный способ создать новую ветку процесса
и она зачем-то создаётся в отдельном адресном пространстве с наследованием содержимого памяти родителя, что приводит к факапу (напр, в джаве)
идиотизм это рассуждать не читая документацию. Я перечислил системные вызовы, можно ведь по каждому из вызовов открыть man и прочитать хотя бы пару строк.
Не в курсе про проблему java+fork(). Наследование содержимого памяти тяжело на компах без полноценного MMU, там CoW не сделаешь. Ну в cygwin получается «тяжёлый» fork(), но cygwin это особое извращение.
А что по-твоему — не идиотизм? Как вообще можно создать копию процесса, не дублируя старый?
идиотизм - это вынуждать пользователя создавать новую ветвь процесса через fork
не идиотизм - это нормальная фукнция CreateThread, которая создаёт новую ветвь в том же адресном пространстве БЕЗО ВСЯКОГО COW и запускает в нём указанную функцию.
случай, когда нужно именно создать копию процесса с COW-памятью, мне на практике ещё не встречался
проблема - это мягко сказано, это скорее эпик-фейл: на самых обычных x86-64 компах, под линуксом, когда джава сожрала больше половины оперативки, и твоя джава-программа пытается создать ещё одну ветвь процесса, то Java VM сваливается с OOM
объяснение фейла:
поскольку нормальной функции CreateThread в линуксе нет (или разработчики джавы о ней не знают), то для создания ветви используется fork().
fork поддерживает две независимые копии памяти с логикой CoW (одна у родителя, вторая у потомка)
засада в том, что в джаве есть постоянно работающий сборщик мусора в отдельной ветке, который постоянно что-то мутит с памятью процесса.
и получается так, что ещё до того, как выполнится следующая инструкция после fork() и в родителе, и в потомке, сборщик мусора уже что-то где-то в памяти изменил. ОС, пытаясь сдержать своё обещание держать отдельные копии памяти для родителя и потомка, выполняет логику CoW, создавая вторую копию блока памяти, в который сборщик мусора произвёл запись: у родителя должна остаться новая версия блока (изменённая), а в потомке этот блок памяти должен содержать то, что было на момент форка (неизменённая). и пока ОС выполняет логику CoW для этого блока памяти (берёт неиспользованный блок и создаёт там отдельную копию), сборщик мусора что-то изменяет в каком-то другом блоке памяти. ну, вы поняли - за сборщиком мусора не угнаться, и когда он прошёлся по почти всей памяти процесса, то ОС должна иметь две копии этой памяти. но столько оперативки на компе нет, т.к. мы рассматриваем случай, когда джава уже съела больше половины ОЗУ.
У меня сейчас нет возможности и желания проверить описываемое вами поведение, но если это правда, то это всё на совести разработчиков java.
На самом деле в Линуксе нет fork(), года с 1999 (или раньше). Там в ядра clone(). Ей указывается что именно клонировать, а что оставить шареным (память, файловый дескрипторы, обработчики сигналов и т.д.). Это не posix-совместимо и в обычных программах для потока вычислений используют всякие pthread_create(), но Java могла себе позволить затачиваться под конкретную операционную систему...
прочитал и с ужасом закрыл man
создать ветку процесса через vfork не получится, потому что он блокирует родителя. но иногда не блокирует (на некоторых системах vfork==fork). короче, хрень полная.