Как запустить два процесса одновременно
Здравствуйте! Мне необходимо запустить одновременную трансляцию видео- и аудиопотоков на определенный IP. Подскажите пожалуйста, как запустить два процесса одновременно:
arecord -f cd -D plughw:1,0 | ffmpeg -i — -acodec libmp3lame -ab 8k -ac 1 -re -f rtp rtp://192.168.0.101:8082
avconv -f video4linux2 -s 160×120 -v debug -i /dev/video0 -vcodec mpeg2video -r 25 -pix_fmt yuv420p -me_method epzs -b 2600k -bt 256k -f rtp rtp://192.168.0.101:8083
Каждый из них безостановочно вываливает кучу сообщений и запустить второй процесс одновременно с первым, пока тот не закончится, не получается. Подскажите пожалуйста, как это организовать в скрипте.
MNorin.com
Блог про Linux, Bash и другие информационные технологии
Параллельное выполнение в bash
В большинстве командных оболочек команды выполняются по умолчанию последовательно. И это, в принципе, нормально. Потому что человек с системой взаимодействует последовательно, обычно нет необходимости несколько команд выполнять параллельно. Bash в этом смысле тоже не исключение. Но при автоматизации возможность параллельного выполнения может быть полезной. Давайте посмотрим, как организовать параллельное выполнение в bash.
Использование фонового режима
Для организации параллельной работы нескольких программ часто используется запуск в фоновом режиме при помощи знака амперсанда — &. Например:
Команда будет работать в фоне, при этом из текущей оболочки можно выполнять команды. Таким образом уже можно распараллелить какие-то действия. Можно запустить сразу несколько команд таким образом и дождаться, пока они все отработают. Для ожидания запущенных дочерних процессов используется команда wait. Эта команда без параметров ожидает окончания работы всех дочерних процессов, соответственно, для ожидания окончания 5 процессов понадобится выполнить команду всего 1 раз. В принципе, это легко реализуется через цикл. Например, так:
И результат работы этого скрипта:
Как видите, с виду одинаковые команды завершились не в том порядке, в котором мы их запустили. Давайте посмотрим теперь общее время выполнения скрипта.
Общее время работы скрипта чуть больше 10 секунд, что доказывает, что наши команды выполнились параллельно, а увеличение времени выполнения говорит о том, что они были запущены не в одно и то же время, были небольшие таймауты между запусками. Но они были очень маленькими, поэтому такой запуск пяти процессов занимает практически такое же время, как запуск одного.
Использование пайпа
При использовании пайпов, которые перенаправляют вывод одной программы на вход другой, процессы выполняются параллельно. Отсюда вытекает еще один способ параллельного выполнения нескольких команд — перенаправить между ними какие-то данные с помощью пайпа. Например:
Тут важно помнить вот что: если вам не нужно передавать реально какие-то данные между программами, то надо предварительно убедиться, что входные данные эти программы получат в виде опций командной строки и не будут использовать те данные, которые были переданы им с помощью пайпа. Хотя здесь, в принципе, возможен такой вариант:
Этот вариант до использования в скриптах, естественно, нужно обязательно проверить в ручном режиме и посмотреть в страницах руководств используемых программ (если там есть такая информация), что имеет больший приоритет — опции командной строки или стандартный поток ввода, потому что некоторые программы могут игнорировать командную строку, если данные передаются через стандартный поток ввода.
Параллельное выполнение и ограничение количества фоновых задач в скрипте
Давайте рассмотрим такую практическую задачу — запустить 100 процессов параллельно, но так, чтобы работало одновременно не более 10 процессов. В общем, достаточно простая задача. Предположим, что все процессы работают произвольное количество времени. Пусть запуск одной задачи будет выглядеть как запуск команды sleep со случайным параметром от 0 до 29. Тогда скрипт будет выглядеть следующим образом:
Смысл этого скрипта в целом такой: ограничиваем максимально число дочерних фоновых процессов так, чтобы их одновременно было не более 10. Как только один процесс заканчивает свою работу, запускаем следующий. И так далее, пока не выполним 100 фоновых задач. Для порядка отслеживаем в скрипте окончание работы дочерних процессов после запуска последних, только потом заканчиваем работу самого скрипта.
Таким простым способом можно ограничить количество одновременно запущенных фоновых задач в скрипте и при этом отслеживать, сколько из них в данный момент работают. Чтобы было более понятно, запустите скрипт и увидите, когда запускается следующие итерации цикла, и когда изменяется количество дочерних процессов.
Распараллеливаем процессы для ускорения вычислений и выполнения заданий в Linux

Почти все персональные компьютеры, выпущенные за последние несколько лет, обладают как минимум двухъядерным процессором. Если у тебя, читатель, не очень старый комп или не какой-нибудь бюджетный ноутбук, то, вероятнее всего, ты обладатель многопроцессорной системы. А если еще любишь играть в игры, то тебе доступно около сотни GPU-ядер. Однако львиную долю времени вся эта мощь пылится без дела. Попробуем это исправить.
Введение
Очень редко мы задействуем всю мощь нескольких процессоров (или ядер) для решения повседневных задач, а использование мощного графического процессора чаще всего сводится к компьютерным играм. Лично мне это не по душе: я ведь работаю — почему процессор должен отдыхать? Непорядок. Нужно взять на вооружение все возможности и преимущества многопроцессорников (многоядерников) и распараллеливать все, что можно, сэкономив себе этим уйму времени. А если еще и подключить к работе мощную видеоплату с сотней ядер на борту… которая, конечно, сгодится лишь для узкого круга задач, но все же ускорит вычисления весьма существенно.
Linux в этом плане очень силен. Во-первых, в большинстве дистрибутивов из коробки доступны хорошие инструменты для параллельного выполнения, а во-вторых, написано немало софта, спроектированного с учетом многоядерных систем. О гибкости настройки, думаю, даже не нужно говорить. Единственное, с чем могут возникнуть проблемы, — драйверы на видеокарту, но тут уж ничего не поделаешь.
Для начала определимся с методами распараллеливания. Их существует два: средствами самого приложения, которое для выполнения задачи запускает несколько параллельных потоков (multithreading). Другой метод заключается в запуске нескольких копий приложения, каждая из которых будет обрабатывать определенную порцию данных. Операционная система в данном случае самостоятельно распределит процессы по ядрам или процессорам (multitasking).
Распараллеливаем прямо в терминале
Начнем, пожалуй, с параллельного запуска процессов прямо из окна терминала. Запуск в терминале процессов, работающих длительное время, не представляет проблему. А что, если нужно два таких процесса? «Тоже не проблема, — скажешь ты, — просто запустим второй процесс в другом окне терминала». А если нужно запустить десять или больше? Хм… Первое, что приходит в голову, — использовать утилиту xargs. Если задать ей опцию —max-procs=n, то софтина будет выполнять n процессов одновременно, что нам, конечно же, на руку. Официальный мануал рекомендует использовать вместе с опцией —max-procs группировку по аргументам (опция -n): без этого возможны проблемы с параллельным запуском. Для примера представим, что нам нужно заархивировать кучу больших (или маленьких) файлов:
Сколько времени мы выиграли? Стоит ли заморачиваться с этим? Тут будет уместно привести цифры. На моем четырехъядерном процессоре обычное архивирование пяти файлов, каждый из которых весил около 400 Мб, заняло 1 мин 40 с. С использованием же xargs —max-procs=4 затраченное время сократилось почти в четыре раза: 34 с! Думаю, ответ на вопрос очевиден.
Давай попробуем что-нибудь поинтереснее. Переконвертируем, например, WAV-файлы в MP3 с помощью lame:
Выглядит неуклюже? Согласен. Но параллельное выполнение процессов — это не основная задача xargs, а всего лишь одна из ее возможностей. Кроме того, xargs не очень хорошо ведет себя с передачей специальных символов, как, например, пробел или кавычки. И тут нам на помощь приходит замечательная утилита под названием GNU Parallel. Софтина доступна в стандартных репозиториях, но не рекомендую устанавливать ее оттуда: в репозиториях Ubuntu, например, мне попалась версия двухлетней давности. Лучше скомпилить себе свежую версию с исходников:
Само название утилиты говорит о ее узкой специализации. Действительно, Parallel намного удобнее для распараллеливания, и ее использование выглядит более логично. Приведенный выше пример с применением Parallel вместо xargs превращается в такой:
Кстати, если ты сидишь под Ubuntu или Kubuntu, то пример не будет работать, выдавая непонятные ошибки. Фиксится это добавлением ключа ‘—gnu’ (касается и следующего примера). Подробнее о проблеме читай здесь.
А почему мы не задаем количество одновременно выполняемых процессов? Потому что Parallel сделает это за нас: она определит количество ядер и будет запускать по процессу на ядро. Конечно, можно задать это число и вручную с помощью опции -j. Кстати, если нужно запускать задачу на разных машинах, то для улучшения переносимости удобно задавать эту опцию в формате -j +2, что в данном конкретном случае означает «запускать одновременно на два процесса больше, чем есть вычислительных юнитов в системе».
Если подружить Parallel c Python, то получим мощный инструмент для параллельного выполнения задач. Например, загрузка из Сети веб-страниц и их последующая обработка может выглядеть так:
Но и без Python возможностей у этой утилиты предостаточно. Обязательно почитай man — там очень много интересных примеров.
Кроме Parallel и xargs, конечно, есть еще уйма других утилит со схожим функционалом, но они не умеют ничего такого, чего не умеют первые две.
С этим разобрались. Двигаемся дальше.
Параллельная компиляция
Собирать что-то из исходников — обычное дело для линуксоида. Чаще всего приходится собирать что-то незначительное, для таких проектов никто не думает ни о какой параллельной компиляции. Но иногда попадаются проекты побольше, и ждать окончания сборки приходится почти вечность: сборка, например, Android (AOSP) из исходников (в один поток) длится около пяти часов! Для такого рода проектов нужно пускать в ход все ядра.
Во-первых, думаю, очевидно, что собственно сама компиляция (GCC, например) не распараллеливается. Но большие проекты чаще всего составлены из большого количества независимых модулей, библиотек и прочего, которые можно и нужно компилировать одновременно. Нам, конечно же, не надо думать о том, как распараллелить компиляцию, — об этом позаботится make, но только при условии, что в makefile будут прописаны зависимости. В противном случае make не будет знать, в какой последовательности собирать и что можно собирать одновременно, а что нельзя. И поскольку makefile — это забота разработчиков, для нас все сводится к выполнению команды
после чего make начнет сборку проекта, одновременно запуская до N задач.
Кстати, о выборе значения для параметра -j. В Сети часто рекомендуют использовать число 1,5 * <количество вычислительных юнитов>. Но это не всегда верно. Например, сборка проекта общим весом 250 Мб на моем четырехъядернике быстрее всего прошла со значением параметра -j, равным четырем (смотри скрин).
Зависимость времени компиляции от значения параметра
Чтобы выиграть еще немного времени, можно добавить ключ ‘-pipe’ к GCC. С этим ключом передача данных между разными стадиями компиляции происходит через каналы обмена (pipes), а не через временные файлы, что немного (совсем немного) ускоряет процесс.
Кроме make, можно попробовать также pmake — систему параллельной сборки, написанную на Python. Для юзверей ее использование мало чем отличается от make, а вот для разработчиков она может быть довольно интересной, поскольку имеет более обширные возможности, чем стандартный инструмент.
Параллельный Rsync
Если ты когда-нибудь использовал Rsync для синхронизации огромного количества маленьких файлов с удаленным сервером, то, наверное, заметил приличную задержку на стадии receiving file list. Можно ли ускорить этот этап за счет распараллеливания? Конечно, можно. Много времени здесь уходит на задержки в работе сети. Чтобы минимизировать эти временные потери, мы запустим несколько копий Rsync, а чтобы не копировались одни и те же файлы — натравим каждую копию, например, на отдельный каталог. Для этого заюзаем комбинацию параметров —include и —exclude, например так:
Можно запустить вручную несколько копий в разных терминалах, но можно подключить Parallel:
Турбореактивное копирование файлов по SSH
Как правило, для синхронизации директорий между двумя хостами Rsync запускают поверх SSH. Ускорив SSH-соединение, ускорим и работу Rsync. А SSH можно ускорить за счет использования набора патчей OpenSSH HPN, устраняющих ряд узких мест в механизме буферизации серверной и клиентской части SSH. Кроме того, в HPN используется многопоточная версия алгоритма AES-CTR, что повышает скорость шифрования файлов (активируется флагом -oCipher=aes[128|192|256]-ctr ). Чтобы проверить, установлен ли у тебя OpenSSH HPN, вбей в терминале:
и ищи вход подстроки HPN. Если у тебя оказался обычный OpenSSH, установить HPN-версию можно так:
Затем добавь в /etc/ssh/sshd_config строки:
после чего перезапусти сервис SSH. Теперь снова создай Rsync/SSH/SCP-подключение и оцени выигрыш.
Включаем поддержку HPN
Сжатие файлов
Все те ускорения, что мы проделывали выше, основаны на одновременном запуске нескольких копий одного и того же процесса. Планировщик процессов операционной системы разруливал эти процессы между ядрами (процессорами) нашей машины, за счет чего мы и получали ускорение. Вернемся к примеру, где мы сжимали несколько файлов. Но что, если нужно сжать один огромный файл, да еще и медленным bzip2? К счастью, сжатие файлов очень хорошо поддается параллельной обработке — файл разбивается на блоки, и они сжимаются независимо. Однако стандартные утилиты, вроде gzip и bzip2, такого функционала не имеют. Благо есть много сторонних продуктов, умеющих это. Рассмотрим только два из них: параллельный аналог gzip — pigz и аналог bzip2 — pbzip2. Две эти утилиты доступны в стандартных репозиториях Ubuntu.
Использование pigz абсолютно ничем не отличается от работы с gzip, кроме возможности указать количество потоков и размер блока. Размер блока в большинстве случаев можно оставить дефолтный, а как количество потоков желательно указать число, равное (или на 1–2 больше) количеству процессоров (ядер) системы:
Выполнение этой команды над файлом backup.tar весом в 620 Мб заняло у меня 12,8 с, результирующий же файл весил 252,2 Мб. Обработка того же файла с помощью gzip:
заняла 43 с. Результирующий файл при этом весил всего-то на 100 Кб меньше, по сравнению с предыдущим: 252,1 Мб. Опять же мы получили почти четырехкратное ускорение, что не может не радовать.
Pigz умеет распараллеливать только сжатие, но не распаковку, чего не скажешь про pbzip2 — который умеет и то и другое. Использование утилиты аналогично ее непараллельному варианту:
Обработка того же файла backup.tar заняла у меня 38,8 с, размер результирующего файла — 232,8 Мб. Сжатие с использованием обычного bzip2 заняло 1 мин 53 с, при размере файла в 232,7 Мб.
Как я уже говорил, с pbzip2 можно ускорить и распаковку. Но тут нужно учесть один нюанс — параллельно распаковывать можно только то, что до этого было запаковано параллельно, то есть только архивы, созданные с помощью pbzip2. Распаковка в несколько потоков обычного bzip2-архива будет произведена в один поток. Ну и еще немного цифр:
- обычная распаковка — 40,1 с;
- распаковка в пять потоков — 16,3 с.
Шифрование
По умолчанию для шифрования домашней директории в Ubuntu и всех производных дистрибутивах используется eCryptfs. На момент написания статьи eCryptfs не поддерживал мультипоточности. И это особенно заметно в папках с большим количеством маленьких файлов. Так что если у тебя многоядерник, то eCryptfs использовать нецелесообразно. Лучшей заменой будет использование систем dm-crypt или Truecrypt. Правда, они могут шифровать только целые разделы или контейнеры, но зато поддерживают мультипоточность.
Если хочешь зашифровать только определенную директорию, а не целый диск, то можешь попробовать EncFS. Она очень похожа на eCryptfs, но работает, в отличие от последней, не в режиме ядра, а с использованием FUSE, что делает ее потенциально медленнее, чем eCryptfs. Но она поддерживает мультипоточность, поэтому на многоядерных системах будет выигрыш в скорости. К тому же она очень проста в установке (доступна в большинстве стандартных репозиториев) и использовании. Нужно всего-то выполнить
ввести парольную фразу, и все: в .crypt-raw будут лежать зашифрованные версии файлов, а в crypt — незашифрованные. Чтобы размонтировать EncFS, выполни:
Конечно, все это можно автоматизировать. О том, как это сделать, можно почитать здесь.
Люблю смотреть, как ядра пашут
Загружать-то процессор на полную мы загружаем, но нужно иногда и мониторить его работу. В принципе, почти каждый дистрибутив имеет хорошую оснастку для мониторинга использования процессора, включая информацию о каждом отдельном ядре или процессоре. В Kubuntu, например, KSysGuard очень удачно отображает текущую загруженность ядер (смотри скрин «KSysGuard на четырехъядерной системе»).
KSysGuard на четырехъядерной системе
Но есть и другие интересные утилиты, позволяющие созерцать работу процессора. Любителям консольных решений по душе придется htop — более красочный и интерактивный аналог top. Еще советую обратить внимание на Conky — мощный и легко настраиваемый системный монитор. Очень легко его настроить для мониторинга загруженности каждого ядра и процессора в целом. Для каждого ядра можно вывести отдельный график. На скриншоте можешь посмотреть мой вариант конфигурации утилиты.
Вот так выглядит Conky
Htop в действии
Содержимое соответствующего конфигурационного файла я выложил сюда. В Сети, кстати, полно интересных конфигов, которые можно взять за основу и переделать под себя.
Но эти утилиты дают лишь информацию о загруженности, чего часто может оказаться недостаточно. Mpstat из набора sysstat выдает более интересную информацию, как, например, время простоя каждого ядра, время, потраченное на ожидание ввода/вывода, или время, затраченное на обработку прерываний.
Вывод утилиты mpstat
GPU не только для игр
Не секрет, что современные GPU обладают очень большими вычислительными мощностями. Но из-за того, что ядра GPU имеют особую архитектуру и ограниченный набор доступных команд, GPU пригоден лишь для решения узкого круга задач. Раньше выполнять вычисления на GPU могли только гуру шейдеров. Сейчас же производители видеокарт делают все возможное, чтобы упростить жизнь энтузиастов и разработчиков, желающих задействовать мощности графических процессоров в своих проектах: CUDA от NVIDIA, AMD FireStream, открытый стандарт OpenCL. С каждым годом вычисления на GPU становятся все доступнее и доступнее.
Вычисление хешей
На сегодняшний день из запускаемых на GPU задач популярнее всего, наверное, вычисление хешей. А все это из-за Bitcoin-майнинга, который, собственно, и заключается в вычислении хешей. Большинство Bitcoin-майнеров доступны под Linux. Если ты хочешь майнить Bitcoin’ы и если твой графический процессор поддерживает OpenCL (если поддерживает CUDA, то и OpenCL тоже), тогда рекомендую обратить внимание на bfgminer: он быстр, удобен и функционален, хоть и не так уж прост в настройке.
Ускорение Snort за счет GPU
Но не Bitcoin’ом единым живем. Ничто не мешает использовать мощности GPU для брутфорса хешей (с целью узнать свой забытый пароль, конечно же, не более). В решении этой задачи хорошо зарекомендовала себя утилита oclHashcat-plus — настоящий комбайн по бруту хешей. Умеет подбирать хеши MD5 с солью и без соли, SHA-1, NTLM, кешированные пароли домена, пароли баз данных MySQL, пароли GRUB, и это еще даже не половина списка.
Шифрование на GPU
Очень интересное применение мощностей графических процессоров представили нам студенты Вэйбинь Сунь (Weibin Sun) и Син Линь (Xing Lin) из университета Юты в рамках проекта KGPU. Суть проекта заключается в переносе исполнения некоторых частей кода ядра Linux на CUDA-совместимый GPU. Первым разработчики решили вынести на GPU алгоритм AES. К сожалению, на этом развитие проекта и остановилось, хотя разработчики обещали продолжить работу. Но помимо этого, уже существующую наработку можно использовать для ускорения AES-шифрования в eCryptfs и dm-crypt, жаль только, что ядро версии 3.0 и выше не поддерживается.
Мониторинг производительности GPU
А почему бы и нет? Конечно, загруженность каждого GPU ядра узнать не удастся, но хоть какую-то информацию о происходящем на GPU получить можно. Программка CUDA-Z (почти аналог Windows-программы GPU-Z), кроме разной статической информации о GPU, умеет получать и динамическую: текущую скорость обмена данными между графическим процессором и машиной, а также общую производительность всех ядер GPU в флопсах.
Вкладка CUDA-Z с информацией о производительности GPU
Выводы
Многоядерные или же многопроцессорные рабочие станции достаточно давно вошли в нашу повседневную жизнь — пора менять и наш однопоточный подход при работе с ними. Ведь распараллеливание задач на таких системах дает нам огромный выигрыш времени, в чем мы и убедились.
Полезные ссылки
- Тюнинг JVM для увеличения производительности Java EE приложений на многоядерной системе:
bit.ly/JavaTuning - Измерение производительности многоядерных CPU при помощи MPI-тестов: bit.ly/MPIbenchmark
- Если нечем занять свой компьютер, отдай вычислительные мощности на поиск лекарств, изучение глобального потепления и другие интересные научные исследования: https://boinc.berkeley.edu
Впервые опубликовано в журнале «Хакер» от 10/2013.
How do you run multiple programs in parallel from a bash script?
But that runs prog1 then waits until prog1 ends and then starts prog2.
So how can I run them in parallel?
![]()
![]()
19 Answers 19
- Start prog1 .
- Send it to background, but keep printing its output.
- Start prog2 , and keep it in foreground, so you can close it with ctrl-c .
- When you close prog2 , you’ll return to prog1 ‘s foreground, so you can also close it with ctrl-c .
To run multiple programs in parallel:
If you need your script to wait for the programs to finish, you can add:
at the point where you want the script to wait for them.
If you want to be able to easily run and kill multiple process with ctrl-c , this is my favorite method: spawn multiple background processes in a (…) subshell, and trap SIGINT to execute kill 0 , which will kill everything spawned in the subshell group:
You can have complex process execution structures, and everything will close with a single ctrl-c (just make sure the last process is run in the foreground, i.e., don’t include a & after prog1.3 ):
If there is a chance the last command might exit early and you want to keep everything else running, add wait as the last command. In the following example, sleep 2 would have exited first, killing sleep 4 before it finished; adding wait allows both to run to completion:
You can use wait :
It assigns the background program PIDs to variables ( $! is the last launched process’ PID), then the wait command waits for them. It is nice because if you kill the script, it kills the processes too!
Or if you prefer:
- Watch the intro video for a quick introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
- Walk through the tutorial (man parallel_tutorial). Your command line will love you for it.
- Read: Ole Tange, GNU Parallel 2018 (Ole Tange, 2018).
![]()
xargs -P <n> allows you to run <n> commands in parallel.
While -P is a nonstandard option, both the GNU (Linux) and macOS/BSD implementations support it.
The following example:
- runs at most 3 commands in parallel at a time,
- with additional commands starting only when a previously launched process terminates.
The output looks something like:
The timing shows that the commands were run in parallel (the last command was launched only after the first of the original 3 terminated, but executed very quickly).
The xargs command itself won’t return until all commands have finished, but you can execute it in the background by terminating it with control operator & and then using the wait builtin to wait for the entire xargs command to finish.
BSD/macOS xargs requires you to specify the count of commands to run in parallel explicitly, whereas GNU xargs allows you to specify -P 0 to run as many as possible in parallel.
Output from the processes run in parallel arrives as it is being generated, so it will be unpredictably interleaved.
- GNU parallel , as mentioned in Ole’s answer (does not come standard with most platforms), conveniently serializes (groups) the output on a per-process basis and offers many more advanced features.
Redirect errors to separate logs.
Here is a function I use in order to run at max n process in parallel (n=4 in the example):
If max_children is set to the number of cores, this function will try to avoid idle cores.
This works beautifully for me (found here):
It outputs all the logs of each command intermingled (which is what I wanted), and all are killed with ctrl+c.
There is a very useful program that calls nohup.
I had a similar situation recently where I needed to run multiple programs at the same time, redirect their outputs to separated log files and wait for them to finish and I ended up with something like that:
![]()
You can try ppss (abandoned). ppss is rather powerful — you can even create a mini-cluster. xargs -P can also be useful if you’ve got a batch of embarrassingly parallel processing to do.
![]()
Process Spawning Manager
Sure, technically these are processes, and this program should really be called a process spawning manager, but this is only due to the way that BASH works when it forks using the ampersand, it uses the fork() or perhaps clone() system call which clones into a separate memory space, rather than something like pthread_create() which would share memory. If BASH supported the latter, each «sequence of execution» would operate just the same and could be termed to be traditional threads whilst gaining a more efficient memory footprint. Functionally however it works the same, though a bit more difficult since GLOBAL variables are not available in each worker clone hence the use of the inter-process communication file and the rudimentary flock semaphore to manage critical sections. Forking from BASH of course is the basic answer here but I feel as if people know that but are really looking to manage what is spawned rather than just fork it and forget it. This demonstrates a way to manage up to 200 instances of forked processes all accessing a single resource. Clearly this is overkill but I enjoyed writing it so I kept on. Increase the size of your terminal accordingly. I hope you find this useful.