Русские Блоги
Понимание / dev / shm
1. / dev / shm теория
Виртуальная машина состоит из двух частей: RM + Swap, поэтому максимальное пространство хранения tmpfs не превышает (размер RM + размер Swap). Но для самой tmpfs он не знает, является ли используемое им пространство RM или Swap, и все они управляются подсистемой vm ядра. Размер tmpfs по умолчанию равен половине RM. Если ваша физическая память равна 1024M, то размер tmpfs по умолчанию составляет 512M. В нормальных условиях он настроен на размер меньше физической памяти. Размер конфигурации tmpfs на самом деле не занимает эту память.Если в каталоге / dev / shm / нет файла, то занимаемая им память фактически равна 0 байтам, если это максимум 1 ГБ, в нем содержится 100 МБ файлов, а остальные 900M все еще может использоваться другими приложениями, но занимаемая им память 100M не будет разделяться системой. При удалении файлов в tmpfs драйвер файловой системы tmpfs динамически сокращает файловую систему и освобождает ресурсы виртуальной машины.
У tmpfs есть следующие преимущества:
1. Размер динамической файловой системы.
2. Еще одним важным преимуществом tmpfs является его молниеносная скорость. Поскольку типичная файловая система tmpfs полностью находится в оперативной памяти, чтение и запись могут быть практически мгновенными.
3. Данные tmpfs не будут сохранены после перезапуска, поскольку виртуальная память по своей природе является энергозависимой. Поэтому необходимо сделать несколько сценариев для выполнения таких операций, как загрузка и привязка.
Во-вторых, измените размер / dev / shm
Максимальная половина размера памяти по умолчанию может быть недостаточной в некоторых случаях, и число inode по умолчанию, как правило, невелико. Как правило, вам нужно увеличить его. Вы можете использовать команду mount для управления им.
Если вам нужно постоянно изменять значение / dev / shm, вам нужно изменить / etc / fstab
Три, / dev / shm приложение
Сначала создайте папку tmp в / dev / shm, а затем свяжите ее с фактическим / tmp
Как правильно пользоваться /dev/shm в современном линуксе?
mount | grep shm выдаёт:
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec)
Соответствующая строка в /etc/fstab :
shm /dev/shm tmpfs nodev,nosuid,noexec 0 0
Можно ли просто писать временные файлы в эту директорию не заморачиваясь с монтированием каких-либо ещё?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
Забыл уточнить: ядро 2.6.28.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
В упор не вижу никаких директорий. Ты хочешь _временно_ хранить фалы в оперативке?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
Вот это для ознакомления можно почитать.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Ты хочешь _временно_ хранить фалы в оперативке?
/dev/shm это классический tmpfs
Re: Как правильно пользоваться /dev/shm в современном линуксе?
>/dev/shm это классический tmpfs
в который монтируется корневая фс при работе initramfs
Re: Как правильно пользоваться /dev/shm в современном линуксе?
я правильно её использую так:
scyld-debian:/# cat /etc/initramfs-tools/scripts/init-bottom/scyld
#!/bin/sh
PREREQ=»udev»
prereqs()
<
echo «$PREREQ»
>
modprobe aufs
modprobe squashfs
modprobe loop
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> В упор не вижу никаких директорий.
К этой директории на достаточно новых ядрах по умолчанию подмонтирована файловая система tmpfs размером 0,5 объёма физической памяти.
> Ты хочешь _временно_ хранить фалы в оперативке?
Спасибо, но там рассказывают о ramfs по состоянию на 2001 год. Разве от неё не отказались несколько лет назад в пользу tmpfs?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
>>/dev/shm это классический tmpfs
> в который монтируется корневая фс при работе initramfs
Я спрашиваю уже про нормальное функционирование системы, когда загрузка закончилась.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Можно ли просто писать временные файлы в эту директорию не заморачиваясь
Можно, но она не для этого предназначена.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> я правильно её использую так:
Спасибо, но я спрашиваю не про загрузку, а про работу от имени непривилегированного пользователя. Который может даже не иметь права на команду mount.
Скажем, программе надо создать временный файл. Который будет нужен всего в течении нескольких секунд или минуты. И который должен быть доступен нескольким другим программам. Потом его можно со спокойной совестью удалить. Писать на жёсткий диск? Файлов таких много. Объём невелик (от десятков килобайт до нескольких мегабайт), хранить их в памяти позволяет. Желательно, чтобы программа «просто работала» на как можно большем числе компьютеров и не требовала прав рута для установки.
Имеется директория /dev/shm/ с правами drwxrwxrwt. Можно ли туда писать файлы с уникальными именами, или какие-то программы строятся из рассчёта, что /dev/shm/ пуста, и никто кроме них ею не пользуется? Можно ли ожидать, что она будет доступна на большинстве машин? Что о ней говорят основополагающие документы наподобие LSB?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Можно, но она не для этого предназначена.
Спасибо. Как осуществлять доступ к этому объекту из других программ? Просто вызывать shm_open с тем же именем? Останется ли объект существовать, после завершения породившего его процесса? Существует ли способ перенаправить ввод-вывод программы, использующей просто open() в такой объект, или для этого надо переписать программу?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
Не вижу ничего, мешающего работать с shm. Я, например, при перекодировании звуковых файлов храню временные файлы там. Если оперативки гигов 8, можно вообще выделить под shm 6гигов, копировать туда образ DVD и заниматься перекодированием в avi, расположенном там же 🙂
(давно о таком мечтаю, но денег на реализацию нет 🙁 )
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Спасибо. Как осуществлять доступ к этому объекту из других программ? Просто вызывать shm_open с тем же именем? Останется ли объект существовать, после завершения породившего его процесса?
Для Линукса, ответы на все вопросы «да», но сами вопросы говорят о том, что тебе не нужен /dev/shm. Если очень хочешь tmpfs, смонтируй ее на /tmp
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> сами вопросы говорят о том, что тебе не нужен /dev/shm
Тогда что мне нужно?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Для Линукса, ответы на все вопросы «да»
Спасибо. Я правильно понял, что подмена open() невозможна?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
>> сами вопросы говорят о том, что тебе не нужен /dev/shm
> Тогда что мне нужно?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> По-моему, тебе нужен обычный временный файл.
Насколько будет различаться время чтения из временного файла в памяти и временного файла на диске?
Re: Как правильно пользоваться /dev/shm в современном линуксе?
>Спасибо, но я спрашиваю не про загрузку, а про работу от имени непривилегированного пользователя. Который может даже не иметь права на команду mount.
если б ты читал не по диагонали, ты бы всё понял и не тупил.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> Насколько будет различаться время чтения
Померял. На полутора гигабайтах временных файлов разница в полтора-два раза.
Re: Как правильно пользоваться /dev/shm в современном линуксе?
> если б ты читал не по диагонали
Что из этого скрипта может повторить пользователь, не имеющий прав на mount и sudo? По-моему, ничего.
Что из создаваемого этим скриптом может быть полезно пользователю, не имеющему прав на sudo и mount?
Создаётся директория /boot.scyld, к ней монтируется tmpfs. Создаётся директория /root/dev/shm, к ней тоже монтируется tmpfs, затем в эту директорию перемещается то, что было смонтировано в /boot.scyld. И? Что из них останется после загрузки?
При чём тут squashfs и aufs? Похоже, к использованию tmpfs они не относятся, здесь они решают задачи с ней напрямую несвязанные.
Как это соотносится с конфигурацией компьютера без initramfs? Тоже не ясно.
Когда следует использовать /dev /shm /, и когда следует использовать /tmp /?
6 ответов
Помните, что /dev/shm может быть частью файловой системы /tmp вместо отдельного монтирования и, следовательно, может расти по мере необходимости. Размер / ограничен избыточным ОЗУ в системе, и, следовательно, у вас скорее всего будет нехватка места в этой файловой системе.
В порядке убывания tmpfs вероятность:
Поскольку вы задаете вопрос о конкретной точке монтирования Linux tmpfs для Linux в сравнении с портально определенным каталогом, который может быть tmpfs (в зависимости от вашего sysadmin и того, что по умолчанию для вашего дистрибутива), ваш вопрос имеет два аспекта, которые другие ответы подчеркивали по-разному:
Передовой опыт
Консервативное издание (см. условные обозначения из FHS и обычное использование):
Где tmpfs превосходит
Где tmpfs соответствует
Какие tmpfs не могут помочь вам с
Где tmpfs sux
Сохранение холодных данных. У вас может возникнуть соблазн подумать, что работа с файлами вне свопа так же эффективна, как и обычная файловая система, но есть несколько причин, почему это не так:
Хорошо, вот реальность.
Оба tmpfs и нормальная файловая система представляют собой кеш памяти на диске.
tmpfs использует память и swapspace, поскольку она поддерживает хранилище, в файловой системе используется определенная область диска, и не ограничено в размерах файловой системы, вполне возможно, что на машине с размером меньше GB если у вас достаточно swappace.
Разница заключается в том, когда данные записываются на диск. Для tmpfs данные записываются ТОЛЬКО, когда память становится слишком полной или данные вряд ли будут использоваться в ближайшее время. Большинство обычных файловых систем Linux OTOH всегда имеют более или менее согласованный набор данных на диске, поэтому, если пользователь вытаскивает вилку, они не теряют все.
Эта частая контрольная точка означает, что ненужные данные постоянно записываются на диск, даже для /tmp.
Итак, в результате вам нужно создать пространство подкачки так же сильно, как вам нужно /tmp (даже если вам нужно создать файл подкачки), и использовать это пространство для монтирования tmpfs требуемого размера на /tmp.
НИКОГДА не используйте /dev /shm.
Если вы используете его для очень маленьких (возможно, mmap’d) IPC-файлов, и вы уверены, что он существует (это не стандарт), и у машины более чем достаточно памяти + swap.
Используйте /tmp /для временных файлов. Используйте /dev /shm /, если вам нужна общая память (т. Е. Межпроцессная связь через файлы).
Вы можете полагаться на /tmp /там, но /dev /shm /является относительно недавней версией Linux.
/dev /shm используется для общих драйверов и программ для отдельных виртуальных систем памяти.
Если вы создаете программу, требующую кучи виртуальной памяти, которая должна быть сопоставлена с виртуальной памятью. Это удваивается, поэтому, если вам нужно несколько процессов или потоков, чтобы иметь возможность безопасного доступа к этой памяти.
Дело в том, что только потому, что драйвер использует для него специальную версию tmpfs, не означает, что вы должны использовать его как общий раздел tmpfs. Вместо этого вам нужно просто создать другой раздел tmpfs, если вы хотите его для своего временного каталога.
В PERL, имеющем минимум 8 ГБ на любой машине (все работает под управлением Linux Mint), я считаю, что это хорошая привычка делать сложные алгоритмы на основе DB_File (структура данных в файле) с миллионами чтения и записи, используя /DEV /шй
В других языках, не имеющих повсюду, чтобы избежать запусков и остановок в сетевой передаче (работая локально на файле, который находится на сервере в атмосфере клиент-сервер), используя пакетный файл некоторого типа, я скопирует весь файл (300-900 МБ) сразу в /dev /shm, запустит программу с выходом в /dev /shm, запишет результаты на сервер и удалит из /dev /shm
Естественно, если бы у меня было меньше ОЗУ, я бы этого не делал. Обычно файловая система in-memory /dev /shm читается как размер, равный половине вашей свободной RAM. Однако обычное использование ОЗУ является постоянным. Таким образом, вы действительно не могли сделать это на устройстве с 2 ГБ или меньше. Чтобы перефразировать гиперболу, в ОЗУ часто бывают вещи, которые даже система не сообщает хорошо.
gentoo: миграция с eudev на mdev
Если вы используете gentoo и отслеживаете уведомления о грядущих изменениях, то еще в июле вы могли видеть, что с нового года gentoo перестает поддерживать eudev. Если вы попытаетесь обновить систему сейчас, вы увидите
К сожалению переезд с eudev на альтернативы имеет свои особенности, которые мне хочется осветить в этом посте пока память свежа. Мне давно было интересно попробовать mdev, так что новость о конце поддержки eudev я расценил как намек на то, что пора исполнять задуманное. Важное замечание: у меня gentoo работает на headless серверах. Если вам нужно обновить десктопную машину все может быть несколько сложнее, читайте документацию.
Первая проблема состояла в том, что система хотела поставить sys-fs/static-dev, но не могла этого сделать с вот такой ошибкой:
В https://bugs.gentoo.org/107875#c25 дается решение для выхода из этой ситуации:
Теперь пакет поставлен и можно заниматься переходом на mdev. Начнем с того, что убедимся, что у нас ничего не завязано на udev, в противном случае перейти на mdev не получится.
Проверим, что нет неожиданных зависимостей от udev. У меня это выглядело так:
Убираем udev из use:
При этом сохранится старая версия /etc/portage/make.conf, так что вы легко проверите, что изменение именно то, которое нужно, и при необходимости вернетесь на старый конфиг.
Теперь можно сделать холостой прогон пересборки мира:
Если в выводе нет ошибок и неожиданных пакетов, то можно продолжать.
Для начала нам надо замаскировать sys-fs/udev
Теперь можно добавить поддержку static и mdev для построения busybox
Оказывается надо чуть обновить установки построения некоторых библиотек. Делаем это, запускаем emerge еще раз, в моем случае все собралось без проблем.
Теперь можно включить запуск mdev при инициализации системы и выключить udev и udev-trigger (про последний официальная документация ничего не пишет).
Важный момент: у меня на одной из машин использовались predictable interface names и интерфейс назывался enp1s0. После перехода на mdev этот интерфейс стал eth0. Я не переименовал файл в /etc/init.d и не поправил /etc/conf.d/net, так что после перезагрузки пришлось воспользоваться сериальной консолью для логина и исправления. Если у вас используются predictable interface names не повторите моей ошибки.
Теперь можно перезагрузиться.
Если все прошло хорошо, то можно пересобрать систему
Знакомство с межпроцессным взаимодействием на Linux
Межпроцессное взаимодействие (Inter-process communication (IPC)) — это набор методов для обмена данными между потоками процессов. Процессы могут быть запущены как на одном и том же компьютере, так и на разных, соединенных сетью. IPC бывают нескольких типов: «сигнал», «сокет», «семафор», «файл», «сообщение»…
Отступление: данная статья является учебной и расчитана на людей, только еще вступающих на путь системного программирования. Ее главный замысел — познакомиться с различными способами взаимодействия между процессами на POSIX-совместимой ОС.
Именованный канал
Для передачи сообщений можно использовать механизмы сокетов, каналов, D-bus и другие технологии. Про сокеты на каждом углу можно почитать, а про D-bus отдельную статью написать. Поэтому я решил остановиться на малоозвученных технологиях отвечающих стандартам POSIX и привести рабочие примеры.
Рассмотрим передачу сообщений по именованным каналам. Схематично передача выглядит так:
Для создания именованных каналов будем использовать функцию, mkfifo():
Примечание: mode используется в сочетании с текущим значением umask следующим образом: (mode &
umask). Результатом этой операции и будет новое значение umask для создаваемого нами файла. По этой причине мы используем 0777 (S_IRWXO | S_IRWXG | S_IRWXU), чтобы не затирать ни один бит текущей маски.
Как только файл создан, любой процесс может открыть этот файл для чтения или записи также, как открывает обычный файл. Однако, для корректного использования файла, необходимо открыть его одновременно двумя процессами/потоками, одним для получение данных (чтение файла), другим на передачу (запись в файл).
Пример
mkfifo.c
Мы открываем файл только для чтения (O_RDONLY). И могли бы использовать O_NONBLOCK модификатор, предназначенный специально для FIFO файлов, чтобы не ждать когда с другой стороны файл откроют для записи. Но в приведенном коде такой способ неудобен.
Компилируем программу, затем запускаем ее:
В соседнем терминальном окне выполняем:
В результате мы увидим следующий вывод от программы:
Разделяемая память
Следующий тип межпроцессного взаимодействия — разделяемая память (shared memory). Схематично изобразим ее как некую именованную область в памяти, к которой обращаются одновременно два процесса:
Для выделения разделяемой памяти будем использовать POSIX функцию shm_open():
Функция возвращает файловый дескриптор, который связан с объектом памяти. Этот дескриптор в дальнейшем можно использовать другими функциями (к примеру, mmap() или mprotect()).
Целостность объекта памяти сохраняется, включая все данные связанные с ним, до тех пор пока объект не отсоединен/удален (shm_unlink()). Это означает, что любой процесс может получить доступ к нашему объекту памяти (если он знает его имя) до тех пор, пока явно в одном из процессов мы не вызовем shm_unlink().
После создания общего объекта памяти, мы задаем размер разделяемой памяти вызовом ftruncate(). На входе у функции файловый дескриптор нашего объекта и необходимый нам размер.
Пример
Следующий код демонстрирует создание, изменение и удаление разделяемой памяти. Так же показывается как после создания разделяемой памяти, программа выходит, но при следующем же запуске мы можем получить к ней доступ, пока не выполнен shm_unlink().
shm_open.c
После создания объекта памяти мы установили нужный нам размер shared memory вызовом ftruncate(). Затем мы получили доступ к разделяемой памяти при помощи mmap(). (Вообще говоря, даже с помощью самого вызова mmap() можно создать разделяемую память. Но отличие вызова shm_open() в том, что память будет оставаться выделенной до момента удаления или перезагрузки компьютера.)
Компилировать код на этот раз нужно с опцией -lrt:
Смотрим что получилось:
Аргумент «create» в нашей программе мы используем как для создания разделенной памяти, так и для изменения ее содержимого.
Зная имя объекта памяти, мы можем менять содержимое разделяемой памяти. Но стоит нам вызвать shm_unlink(), как память перестает быть нам доступна и shm_open() без параметра O_CREATE возвращает ошибку «No such file or directory».
Семафор
Семафор — самый часто употребляемый метод для синхронизации потоков и для контролирования одновременного доступа множеством потоков/процессов к общей памяти (к примеру, глобальной переменной). Взаимодействие между процессами в случае с семафорами заключается в том, что процессы работают с одним и тем же набором данных и корректируют свое поведение в зависимости от этих данных.
Семафор со счетчиком
Смысл семафора со счетчиком в том, чтобы дать доступ к какому-то ресурсу только определенному количеству процессов. Остальные будут ждать в очереди, когда ресурс освободится.
Итак, для реализации семафоров будем использовать POSIX функцию sem_open():
В функцию для создания семафора мы передаем имя семафора, построенное по определенным правилам и управляющие флаги. Таким образом у нас получится именованный семафор.
Имя семафора строится следующим образом: в начале идет символ «/» (косая черта), а следом латинские символы. Символ «косая черта» при этом больше не должен применяться. Длина имени семафора может быть вплоть до 251 знака.
Если нам необходимо создать семафор, то передается управляющий флаг O_CREATE. Чтобы начать использовать уже существующий семафор, то oflag равняется нулю. Если вместе с флагом O_CREATE передать флаг O_EXCL, то функция sem_open() вернет ошибку, в случае если семафор с указанным именем уже существует.
Параметр mode задает права доступа таким же образом, как это объяснено в предыдущих главах. А переменной value инициализируется начальное значение семафора. Оба параметра mode и value игнорируются в случае, когда семафор с указанным именем уже существует, а sem_open() вызван вместе с флагом O_CREATE.
Для быстрого открытия существующего семафора используем конструкцию:
, где указываются только имя семафора и управляющий флаг.
Пример семафора со счетчиком
Рассмотрим пример использования семафора для синхронизации процессов. В нашем примере один процесс увеличивает значение семафора и ждет, когда второй сбросит его, чтобы продолжить дальнейшее выполнение.
sem_open.c
В одной консоли запускаем:
В соседней консоли запускаем:
Бинарный семафор
Вместо бинарного семафора, для которого так же используется функция sem_open, я рассмотрю гораздо чаще употребляемый семафор, называемый «мьютекс» (mutex).
Мьютекс по существу является тем же самым, чем является бинарный семафор (т.е. семафор с двумя состояниями: «занят» и «не занят»). Но термин «mutex» чаще используется чтобы описать схему, которая предохраняет два процесса от одновременного использования общих данных/переменных. В то время как термин «бинарный семафор» чаще употребляется для описания конструкции, которая ограничивает доступ к одному ресурсу. То есть бинарный семафор используют там, где один процесс «занимает» семафор, а другой его «освобождает». В то время как мьютекс освобождается тем же процессом/потоком, который занял его.
Без мьютекса не обойтись в написании, к примеру базы данных, к которой доступ могут иметь множество клиентов.
Для использования мьютекса необходимо вызвать функцию pthread_mutex_init():
Функция инициализирует мьютекс (перемнную mutex) аттрибутом mutexattr. Если mutexattr равен NULL, то мьютекс инициализируется значением по умолчанию. В случае успешного выполнения функции (код возрата 0), мьютекс считается инициализированным и «свободным».
Функция pthread_mutex_lock(), если mutex еще не занят, то занимает его, становится его обладателем и сразу же выходит. Если мьютекс занят, то блокирует дальнейшее выполнение процесса и ждет освобождения мьютекса.
Функция pthread_mutex_trylock() идентична по поведению функции pthread_mutex_lock(), с одним исключением — она не блокирует процесс, если mutex занят, а возвращает EBUSY код.
Фунция pthread_mutex_unlock() освобождает занятый мьютекс.
Пример mutex
mutex.c
Данный пример демонстрирует совместный доступ двух потоков к общей переменной. Один поток (первый поток) в автоматическом режиме постоянно увеличивает переменную counter на единицу, при этом занимая эту переменную на целую секунду. Этот первый поток дает второму доступ к переменной count только на 10 миллисекунд, затем снова занимает ее на секунду. Во втором потоке предлагается ввести новое значение для переменной с терминала.
Если бы мы не использовали технологию «мьютекс», то какое значение было бы в глобальной переменной, при одновременном доступе двух потоков, нам не известно. Так же во время запуска становится очевидна разница между pthread_mutex_lock() и pthread_mutex_trylock().
Компилировать код нужно с дополнительным параметром -lpthread:
Запускаем и меняем значение переменной просто вводя новое значение в терминальном окне:
Вместо заключения
В следующих статьях я хочу рассмотреть технологии d-bus и RPC. Если есть интерес, дайте знать.
Спасибо.
UPD: Обновил 3-ю главу про семафоры. Добавил подглаву про мьютекс.








