Linux способ организации вычислений

Обновлено: 04.07.2024

Linux — это семейство операционных систем (ОС), работающих на основе одноименного ядра. Нет одной операционной системы Linux, как, например, Windows или MacOS. Есть множество дистрибутивов (набор файлов, необходимых для установки ПО), выполняющих конкретные задачи.

Кратчайшая история создания Linux

Линус Торвальдс — первый разработчик и создатель Linux. Именно в честь него и была названа ОС. В 1981 году Линус начал работу над собственной ОС семейства Unix. Через три года появилась первая версия, доступная для скачивания. Но тогда она имела очень низкий спрос — ей пользовались буквально несколько человек.

Только через 10 лет ОС Linux получила широкое распространение. Сообщество программистов подхватило идею свободного ПО, специалисты стали помогать развивать проект.

Про логотип

Логотип и талисман Linux — пингвин Tux с желтыми лапами и клювом. В 1996 году разработчики ядра Linux решили выбрать талисман. Торвальдс обмолвился о том, что ему очень нравятся пингвины. Поэтому на логотипе ОС изображен пингвин.


Где нужен Linux?

Веб-серверы

Дистрибутивы Linux практически полностью захватили рынок веб-серверов. Согласно рейтингу аналитического агентства W3Techs, на Linux-серверах развернуты 75,1% сайтов.

Мобильные устройства

ОС Android работает на ядре Linux, поэтому она используется и в мобильных устройствах.

Суперкомпьютеры

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

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

Игровые консоли

Linux занял свою нишу и в игровых консолях, но ориентированных на эту ОС игр пока не так много. Компания Steam работает над исправлением ситуации — разрабатывает операционную систему SteamOS. Она будет поставляться вместе с игровой консолью Steam Machine.

Устройства IoT и умная техника

Многие из них созданы на основе Linux. Так, компания Samsung разработала операционную систему Tize, LG — WebOS, а Panasonic и Philips используют FirefoxOS.

Авиация и транспорт

Во встроенных компьютерах Tesla и машинах с автопилотами Google используется операционная система Linux. ПО для отслеживания трафика в США аналогично разработано на этой ОС, а администрация авиации Америки перешла на нее еще в 2006 году.

Какие компоненты у дистрибутива Linux?

Начинающий программист должен знать структуру Linux, чтобы понимать, как она устроена и каким образом функционирует.

Что это такое, как работает и зачем нужно? Это так называемая главная программа, основная часть ОС. Ядро выступает в качестве посредника между устройствами ПК (видеокартой, процессором, оперативной памятью и пр.) и его ПО. Для этого в коде есть драйверы устройств. Они загружаются в память или подключаются по мере необходимости ресурса определенного устройства. Ядра управляют устройствами, процессами и памятью, обрабатывают системные вызовы.

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

Какие есть виды ядер? Всего выделяют 3 типа: микроядра, монолитные и гибридные.

Микроядро (microkernel)

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

Плюсы:

теоретически высокая степень надежности (по сравнению с другими архитектурами);

низкое потребление памяти;

легкое подключение дополнительных частей ядра (модульность).

Минусы:

низкая скорость из-за постоянного переключения между отдельными частями;

доступность аппаратных средств только через драйверы.

Монолитное ядро (monolithic)

Противоположность микроядра. В памяти ПК всегда размещен весь (либо практически весь) код ядра. Поэтому скорость его работы выше в сравнении с микроядром.

Плюсы:

прямой доступ к аппаратным средствам;

простой обмен данными между процессами;

более высокая скорость реакции процессов.

Минусы:

меньшая степень безопасности (по сравнению с микроядром);

занимает много оперативной памяти.

Гибридное ядро (hybrid)

Комбинация элементов двух ранее описанных архитектур. Для ускорения работы запускает модули операционной системы в пространстве ядра.

Плюсы:

возможность выбора того, что будет функционировать в пространстве ядра и пользователя;

меньший физический размер (в сравнении монолитным ядром);

большая степень гибкости.

Минусы:

более медленная работа;

выпуск драйверов устройств только производителями.

Начните свой путь в IT

Попробуйте себя в программировании, аналитике данных, Data Science и других востребованных специальностях — получите все курсы для входа в IT по цене одного.

Скидка 45% по промокоду BLOG.

Ядро Linux — монолитное, при этом оно заимствует некоторые идеи из микроядерной архитектуры. Это означает, что вся ОС функционирует в пространстве ядра, а драйвера устройств могут легко загружаться (или выгружаться) непосредственно при работе операционной системы.


Железо аппаратное обеспечение ПК с его периферийными устройствами.

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

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

Утилиты — служебные программы, дающие пользователю большую часть функциональных возможностей System OS Linux. Виды утилит: sed, cat, date, vi и прочие.

Компиляторы — технические средства, преобразующие программный код в машинный.

Системные утилиты

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

Системные библиотеки

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

Утилиты разработки ПО

При помощи трех вышеперечисленных компонентов операционная система сможет запускаться и функционировать. Но для обновления и создания новых программ нужно иметь дополнительные библиотеки и инструменты — toolchain. Этот набор программ, инструментов и утилит поможет создавать рабочее приложение из исходных кодов.

Пользовательские программы

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

Плюсы Linux

Минусы Linux

  • Сложности с освоением ОС. Интерфейс большей части версий Linux значительно отличается от привычных Windows и MacOS.


  • Консоль и терминал. Консоль позволяет управлять операционной системой через ввод текста. Там же высвечиваются ответы ОС. Терминал — это современный аналог консоли, он отображается в виде окна на фоне рабочего стола.


  • Требование прав доступа к файлам для работы части программ. Для пользователя это значит, что придется вводить пароль по несколько раз в сутки.
  • Малое количество совместимых игр и программ (по сравнению с Windows). Сегодня это одна из основных причин, почему пользователи не переходят на Linux.

Поддержка и помощь

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

Станьте универсальным специалистом по администрированию Linux с нуля и разверните собственный кластер. Дополнительная скидка 5% по промокоду BLOG.

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

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

В этой статье речь пойдёт о проектах РВ работающих через Интернет, и задействующих компьютеры обычных его пользователей (с их ведома, разумеется) для выполнения разного рода сложных научных расчётов. Участвуя в подобных проектах можно помочь исследовать строение белков и генетических структур, найти лекарство от рака и СПИДа, или даже обнаружить сигналы от внеземных цивилизаций. Обычной работе (или игре) на компьютере это абсолютно не мешает — используются только моменты бездействия.

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

С ЧЕГО ВСЁ НАЧАЛОСЬ

Хотя distributed.net существует очень давно, пределом его мечтаний до сих пор является внимание энтузиастов либо распределённых вычислений как таковых, либо интересующихся криптографией и математикой. А первым проектом, получившим по-настоящему широкую известность и популярность среди "обычных" пользователей, стал, несомненно, SETI@home. Руководители этого проекта предложили всем желающим принять участие в поиске сигналов от внеземной цивилизации. Принцип работы проекта прост: радиотелескоп обсерватории в Аресибо постоянно записывает космический шум, ленты с ним пересылаются в "штаб-квартиру" SETI@home в Беркли, там специальные серверы ("сплиттеры") нарезают данные на мелкие кусочки и рассылают компьютерам участников для обработки.

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

Способ использования "лишних" вычислительных мощностей, заключающийся в повторном обсчёте уже обсчитанного, либо в искусственном и не приносящем особой пользы усложнении обработки одних и тех же данных, не понравился никому, включая самих авторов SETI@home. Гораздо логичнее было бы, если бы проект, у которого на момент обращения компьютера участника за новой порцией данных обсчитывать было бы особо нечего, смог, вместо повторной отправки "старой", уже обработанной порции, честно заявить – "работы сейчас нет, зайдите позже". А клиентская программа участника смогла бы этот ответ понять, и переключиться на помощь какому-нибудь другому проекту – тому, которому дополнительные ресурсы в этот конкретный момент времени действительно нужны и полезны. Данный подход и был реализован авторами SETI@home в их новой платформе для распределённых вычислений, получившей название "BOINC".

Berkeley Open Infrastructure for Internet Computing (BOINC) – это весьма успешная, и уже очень популярная как среди авторов, так и среди участников проектов РВ вычислительная платформа, задача которой – унификация общих по функциональности модулей клиентского и серверного ПО различных проектов. Разработчикам распределённых научных проектов, учёным – специалистам в области биологии, медицины, криптографии и прочих наук – она пришлась по вкусу благодаря тому, что при её использовании им больше не нужно разбираться с такими скучными, и бесконечно далёкими от области их исследований вещами как организация системы регистрации пользователей, разработка системы статистики, отладка взаимодействия клиентского и серверного ПО, и т.д. Всё уже готово – придумано, написано и отлажено авторами BOINC. Остаётся брать и пользоваться. "Брать" предлагается любое ПО BOINC – от клиентского модуля до серверных PHP-скриптов – в исходниках, под лицензией GNU GPL, а "пользоваться" всем этим помогает доступная на сайте BOINC подробнейшая, GNU FDL-лицензированная, документация по созданию на основе этой платформы собственного проекта РВ с нуля.

Итак, пора перейти от теории к практике. Рассмотрим процесс присоединения к работающему на платформе BOINC проекту, на примере запущенного недавно Rosetta@home.

Rosetta@home – это научный проект, проводимый одной из лабораторий университета г. Вашингтона, результатами которого должны стать новые методы (алгоритмы), с помощью которых можно будет с высокой точностью заниматься моделированием, предсказанием и дизайном белков. Наличие проверенных алгоритмов моделирования поможет исследователям разрабатывать лекарства для различных вызываемых нарушениями их структуры болезней. Своим названием проект обязан лежащему в основе его клиентского ПО модулю Rosetta, который был изначально создан для предсказания трёхмерной структуры белка из его аминокислотной последовательности. Со временем, в Rosetta появились функции дизайна и предсказания белковых комплексов. Авторы проекта надеются продолжить постепенно улучшать используемые в Rosetta физическую модель и алгоритмы поиска. А помочь им в этом должны результаты проекта Rosetta@home.

Ядро Rosetta – это физическая модель макромолекулярных взаимодействий и алгоритмов поиска структуры с наименьшей энергией для заданной аминокислотной последовательности (при предсказании структуры белка), комлекса белок-белок (при расчёте стыковки белков), а также поиска аминокислотной последовательности с наименьшей энергией для заданной белковой структуры или комлекса белок-белок (при дизайне белков).

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

Для подключения к проекту, прежде всего нужно указать URL его главной страницы Зарегистрировать новый эккаунт теперь можно и из самого клиента - ранее, для этого приходилось идти на сайт Всё готово!

На следующем экране мастера нужно либо указать E-Mail и пароль к уже созданному в проекте эккаунту, либо зарегистрировать новый (в этом случае пароль попросят ввести дважды).

Стоит отметить, что такая схема авторизации – по E-Mail и паролю – для BOINC относительно нова. Ранее, в основанных на нём проектах использовалась авторизация по секретному Account Key, выступавшему одновременно в роли и уникального идентификатора, и пароля на изменение информации. Кое-где такая схема используется и по сей день (в этом случае клиент BOINC корректно её обнаруживает, и вместо поля с вводом пароля появляется поле для Account Key); существенным её недостатком является отсутствие возможности зарегистрировать новый эккаунт прямо из клиента: необходимо идти на сайт проекта, регистрироваться там, ждать на почту заветный Account Key, и только после этого "подключаться" к проекту в клиенте BOINC.

После создания нового эккаунта, BOINC предложит настроить его параметры, открыв в браузере раздел настроек на сайте проекта. Впрочем, сделать это можно и позже, просто зайдя на сайте проекта в раздел Your Account и указав выбранные при регистрации адрес почты и пароль. Там настраивается выделяемое под проекты BOINC место на диске, можно установить режим работы клиента (допустим, можно сделать, чтобы он работал только в определённые часы), настроить отображаемую им графику (если она есть), и т.д. Во всех проектах BOINC есть не только личный "зачёт", в котором участники выстраиваются в порядке количества набранных ими за обработку блоков данных очков, но и командный, где соревнуются образованные ими команды. Поэтому там же, в разделе настроек эккаунта, есть возможность либо присоединиться к одной из команд (например, к "Russia", объединяющей российских участников проекта), либо создать свою.

Вернёмся к "подключаемому" нами проекту. Сразу после присоединения можно открыть закладку Transfers, и увидеть, что BOINC уже вовсю занялся закачкой модулей, необходимых для участия в Rosetta@home. На сегодняшний момент – это около 17-ти мегабайт. Важно отметить, что подобный объём трафика довольно-таки нетипичен для проектов РВ. Обычно, совокупный объём всех скачиваемых даже во время первоначального присоединения к какому-либо проекту файлов в разы меньше этого значения, а для проектов, занимающихся криптографией или математикой — и вовсё, практически равен нулю.

Самым большим среди россыпи закачиваемых проектом Rosetta@home файлов является собственно расчётный модуль Rosetta – около 7 мегабайт. Очевидно, что загрузка этого модуля потребуется лишь при первоначальном подключении к проекту, ну и при выходе его более новых версий. Вторым по размеру является 6-мегабайтный файл с загадочным названием bbdep02.May.sortlib.gz не обновлялся аж с мая месяца (возможно даже 2002-го года), и не собирается, будем надеяться, слишком часто обновляться и в дальнейшем. Такое поведение довольно часто встречается среди распределённых проектов: скачанные при первоначальном подключении файлы в дальшейшем подвергаются повторному использованию настолько, насколько это является возможным.

На закладке Work уже отображается прогресс обработки текущего блока данных (пока нулевой, состояние – Downloading), затраченное на его обработку время, и так называемый дедлайн – т.е. финальная дата, до которой нужно обязательно посчитать этот блок и вернуть результат, иначе его отправят на обработку кому-нибудь другому.

К сожалению, каких-либо возможностей визуально оценить процесс моделирования (например, своими глазами увидеть создаваемую модель белка) Rosetta@home в данное время не предоставляет. Относится это не только к данному проекту, но и к большинству других, имеющих версии под Linux. Среди опробованных мною BOINC-проектов, графику под Linux на текущий момент показывает только Einstein@home. Однако, в скором времени наверняка можно ожидать изменения ситуации: последняя новость на сайте Rosetta@home сообщает о начавшемся тестировании новой версии скринсейвера (т.е. версии расчётного модуля с полноценной графической частью, наверняка и под Linux тоже). От других проектов тоже, логично ожидать выпуска в скором будущем Linux-версий с поддержкой визуализации расчётов, ведь в большинстве из них она написана под OpenGL, который портируется между платформами довольно просто.

Но, что-то мы отвлеклись. Возвращаемся к клиенту BOINC и видим, что закачка расчётных модулей Rosett'ы уже завершилась, и проект начал расчёты. Теперь можно свернуть окно BOINC Manager'а и заняться своими делами. Rosetta, равно как и любой другой современный проект распределённых вычислений, другим запущенным на компьютере программам никогда не помешает. Чтобы удостовериться, можно открыть top, и увидеть, что процесс rosetta_4.79 хотя и занимает 98% CPU, он при этом имеет самый низкий из возможных приоритет, а значит, как только CPU становится нужен любой другой программе, Rosetta тут же в нужном объёме его освобождает.

Окно BOINC Manager'а с информацией о назначенных компьютеру заданиях

Чтобы воспользоваться основным преимуществом BOINC — динамическим переключением между проектами, нужно присоединиться ещё хотя бы к одному проекту, а лучше — к нескольким. Не знаю кому как, но, по-моему, участвовать одновременно в нескольких проектах гораздо интереснее, чем в каком-то одном. Тем более, что ничего сложного в этом нет: процесс подключения у всех BOINC-проектов идентичен с описанным на примере Rosetta@home.

Проект Climate Prediction, как следует из его названия, занимается моделированием и предсказанием климата на земле. Упрощённо, можно сказать, что результатом работы проекта должен стать "прогноз погоды" на 50 лет вперёд. Его руководители хотят определить, насколько точны существующие методы долговременного предсказания погоды, и насколько сильно на их точность влияют погрешности в исходных данных.

"Мы хотим исследовать небольшие изменения в общей модели, " — говорит координатор проекта, доктор Дэйв Фрэйм из Оксфордского университета. — "Единственный способ сделать это – провести очень много экспериментов, проверить все возможные варианты. То есть сделать то, что заняло бы у суперкомпьютера несколько тысяч лет. Но, решая это как распределенную задачу, мы можем сделать это гораздо быстрее".

Работающий на платформе BOINC вычислительный модуль проекта занимается моделированием долгосрочных изменений климата Земли. Каждый участвующий компьютер получает немного разные входные данные, поэтому результат работы каждого из них будет уникальным. Руководители проекта выберут среди полученных результатов наиболее точно отражающие происходившее до 2000 года, и сделают вывод о наиболее вероятных изменениях, ожидающих нас в будущем.

Этот проект является, несомненно, рекордсменом по количеству скачиваемых при подключении данных. Сразу после присоединения, BOINC-закладка Transfers проинформировала меня о том, что проект climateprediction.net заказал получение файлов на общую "сумму" аж в 44 мегабайта! Поэтому если вам трафик дорог как память, возможно стоит от участия в этом проекте отказаться. Справедливости ради стоит сказать, что единожды закачанный блок данных ClimatePrediction будет считаться очень долго – как минимум месяц, и это на довольно быстром компьютере, причём работающем в круглосуточном режиме. А при расчёте последующих блоков, скачивать большую часть уже полученных данных повторно не потребуется.

Скриншоты приводятся из Windows-версии клиента, Linux-графика, когда она появится (по слухам, для некоторых типов расчётных блоков она уже доступна), вряд ли будет сильно отличаться.

Проект Einstein@home занимается составлением для всего неба атласа излучаемых звёздами-пульсарами гравитационных полей. Такой атлас должен помочь в проверке гипотезы Эйнштейна, предсказывающей теоретическую возможность существования гравитационных волн, возникающих при столкновениях чёрных дыр и взрывах звёзд. Пока, никому из учёных обнаружить эти волны не удалось.

Данные для анализа будут поступать с Лазерно-интерферометрной Обсерватории Гравитационных Полей (LIGO). Рабочая часть задействованной в проекте обсерватории LIGO состоит из двух точнейшим образом установленных зеркал, и путешествующего между ними луча лазера. При наличии волн в гравитационном поле, путь лазера чуть-чуть отклоняется, что позволяет учёным замечать и измерять эти волны. Большее расстояние между зеркалами означает большую чувствительность интерферометра, поэтому зеркала LIGO установлены в четырёх километрах друг от друга. Это позволяет замечать изменения в положении луча лазера вплоть до одной стомиллионной диаметра атома водорода.

Точки - это звёзды, а полоса поперёк сферы — млечный путь. Видны два из трёх маркеров, символизирующих позиции зенитов для собирающих информацию приборов.

Можно сколько угодно говорить о текущем глобальном переходе на BOINC, однако того факта, что существуют как участники, так и разработчики РВ, которым BOINC по разным причинам либо не нравится, либо просто не приносит, по их мнению, никакой пользы по сравнению с "традиционной" архитектурой проекта. Особенно, если последняя уже давно запущена и успешно функционирует.

Среди таких проектов наиболее примечателен Folding@home. Его разработчики сразу же после появления BOINC заявили, что никаких преимуществ от перехода на BOINC они не видят, а когда увидят, тогда просто создадут дополнительную BOINC-версию своего клиента, оставив, наравне с ней, и "классическую". Кстати, на данный момент BOINC-версия клиента этого проекта всё-таки уже существует, и проходит бета-тестирование.

Цель Folding@home — получение более точного представления о болезнях, вызываемых дефектными белками. Изучаются белки, имеющие отношение к болезни Альцгеймера, Паркинсона, диабету типа II, коровьему бешенству и рассеянному склерозу. Поняв, почему возникают дефекты в белках одного типа, ученые смогут выяснить, почему это происходит и с другими белками. Все желающие имеют свободный доступ к результатам. На сайте выкладываются все публикации, ролики смоделированных процессов, и т.п.

Клиент состоит из двух частей: оболочки, и расчётного ядра. Некоторые из расчётных ядер оптимизированы под расширенные наборы инструкций — SSE и 3DNow!, либо SSE2. Но руководители проекта на этом останавливаться не собираются. Исследуется возможность создания версии клиента, использующей для расчётов графический процессор видеокарты, и даже разрабатывается версия, за действующая специальную PCI'ную плату-ускоритель.

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

Владимир Калюжный, Владимир Тарасенко, "Комиздат"

Последнее время все компьютерные издания так или иначе уделяют внимание Linux, свободно распространяемой операционной системе. Многие ведущие производители ПО объявляют о переносе своих продуктов на эту систему. В интернете постоянно появляются новые сайты посвященные этой системе. Налицо бум вокруг Linux, который не только не умолкает а становится все сильнее и мощнее.

Linux и потоки.

Linux, как клон Unix, на данный момент поддерживает многозадачность и многопотоковость, т.е. в системе одновременно может работать несколько задач (процессов), и каждая из задач может выполнятся в несколько потоков. Для начала рассмотрим, что такое поток: поток выполнения - это элемент кода программы, выполняемый последовательно. Большинство приложений - однопотоковые программы. Многопотоковая программа в один момент времени может выполняться в нескольких отдельных потоках. В случае, если задача выполняется на многопроцессорной машине, то все ее потоки могут выполняться одновременно, повышая таким образом производительность выполнения задачи. Производительность многопотокового приложения можно улучшить даже на однопроцессорной системе. Например, если один из потоков приложения блокируется каким-то системным вызовом или ожидает поступления данных, в это время выполняется другой поток.

Между процессами и потоками существуют различия. Под процессами понимается программа находящаяся в стадии выполнения. Скажем, shell в UNIX - это процесс который создается при входе пользователя в систему. Каждая команда создает новый процесс. Согласно терминологии UNIX - это порожденный процесс, который выполняет команду от лица пользователя. Потоки - это часть процесса, и они используют сегменты данных и кода совместно.

Для многопотокового программирования существует два основных стандарта: многопотоковые API Solaris (Sun Microsystems) и API POSIX.1c

В Linux используется API POSIX.1c. Но если быть абсолютно точным, то в Linux присутствует системный вызов clone(), на основе которого и построено API для работы с потоками, соответствующие стандарту POSIX.1c с незначительными исключениями.

Постановка задачи

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

Рассмотрим следующую матрицу A размерностью 4x4:

f(X11) f(X12) f(X13) f(X14)
f(X21) f(X22) f(X23) f(X24)
f(X31) f(X32) f(X33) f(X34)
f(X41) f(X42) f(X43) f(X44)

f(x) - вычисляемая функция
Xij - аргумент

Стандартный подход к вычислениям: достоинства и недостатки

Для вычисления элементов данной матрицы, обычно используют следующий фрагмент кода:

Приняв, что выходные данные (Xij) хранятся в массиве X, а исходные в S:

int SIZE_I = 4;
int SIZE_J = 4;
double X[SIZE_I][SIZE_J];
double S[SIZE_I][SIZE_J];
.
double f(double x)
<
. //какие-то вычисления
>
main_evalution()
<
for (int i=0;i<SIZE_I; P ++i)<>
<
for (int z=0; z<SIZE_J; P ++z)<>
//вычисляем елемент матрицы
X[i][z] = f(S[i][z]);
>
>

После выполнения этого кода, матрица X будет заполнена вычисленными данными. Достоинство данного подхода - простота реализации. Недостаток - при работе на мощной машине (особенно с несколькими процессорами) неполное использование вычислительных ресурсов.

Многопотоковые вычисления: достоинства и недостатки

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

int SIZE_I = 4;
int SIZE_J = 4;
double X[SIZE_I][SIZE_J];
double S[SIZE_I][SIZE_J];
struct DATA_
<
double x;
int i;
int z;
>
typedef struct DATA_ DATA;
double f(double x)
<
//какие-то вычисления
>
void *thread_f(void *arg) //функция для вычисления элемента матрицы
<
DATA* a = (DATA*)arg; //преобразуем данные
X[a->i][a->z] = f([a->x]); //вычисляем
>
main_evalution()
<
pthread_t thread; //идентификатор потока
DATA *arg; //данные для передачи в поток
for (int i=0;i<SIZE_I; P ++i)<>
<
for (int z=0; z<SIZE_J; P ++z)<>
<
// создаем
arg = new DATA;
//инициализируем данные
arg->i = i; arg->z = z; arg->x = S[i][z];
//создаем поток
pthread_create(&thread, NULL, thread_f, (void *)arg);
//переводим в отсоединенное состояние
pthread_detach(thread);
>
>
>

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

Функции для работы с потоками

  • pthread_create(pthread_t *tid, const pthread_attr_t *attr, void*(*function)(void*), void* arg) - создает поток для выполнения функции function. В качестве параметра для потоковой функции передается указатель arg. Индентификатор нового потока возвращается через tid. Поток создается с параметрами attr.
  • pthread_mutex_init(pthread_mutex_t* lock, pthread_mutexattr_t *attr) - инициализирует взаимоисключающую блокировку. attr - содержит аттрибуты для взаимоисключающей блокировки. В случае, если attr == NULL, используются установки по умолчаниию.
  • pthread_mutex_destroy(pthread_mutex_t* lock) - удаляет взаимоисключающую блокировку.
  • pthread_mutex_lock(pthread_mutex_t* lock) - устанавливает блокировку. В случае, если блокировка была установлена другим процессом, текущий процесс останавливается до снятия блокировки другим процессом.
  • pthread_mutex_unlock(pthread_mutex_t* lock) - снимает блокировку.
  • pthread_join(pthread_t tid, void **statusp) - ожидает завершение неотсоединенного процесса, результат возвращаемый функцией сохраняется в statusp.
  • pthread_detach(pthread_t tid) - отсоединяет процесс. Это же можно задать при создании процесса, установив аттрибут detachstate вызовом pthread_attr_setdetachstate.
  • pthread_exit(void *status) - завершает процесс, статус передается вызову pthread_join, подобен exit(). Но вызов exit() в процессе приведет к завершению всей программы.

Процесс завершается двумя путями - вызовом pthread_exit() или завершением потоковой функции. В случае, если процесс неотсоединен, то при его завершении ресурсы, выделенные процессу, не освобождаются до вызова pthread_join(). Если процесс отсоединенный - ресурсы освобождаются по ее завершению.

Пример программы

Данная программа запрашивает у пользователя параметры матрицы аргументов, и используя потоки, заполняет матрицу результатами вычислений.

Данную программу необходимо компилировать с библиотекой pthread (именно в ней находятся все функции для работы с потоками) и задав _REENTRANT:

g++ -D_REENTRANT -o threads threads.c -lpthread

Данный код проверялся на RedHat Linux 6.0

pthread_mutex_t lock; //Исключающая блокировка

// Функция для вычислений
double f(float x)
<
if (x>0) return log(x);
else return x;
>
// Потоковая функция для вычислений
void *thread_f(void *arg)
<
DATA* a = (DATA*) arg;

X[a->i][a->z] = f(a->x);
// устанавливаем блокировку
pthread_mutex_lock(&lock);
// изменяем глобальную переменную
++all;
// снимаем блокировку
pthread_mutex_unlock(&lock);

delete a; // удаляем свои данные
return NULL;
>
// Потоковая функция для ввода
void *input_thr(void *arg)
<
DATA* a = (DATA*) arg;
//pthread_mutex_lock(&lock);
printf("S[%d][%d]:", a->i, a->z);
scanf("%f", &S[a->i][a->z]);
//pthread_mutex_unlock(&lock);
delete a;
return NULL;
>
int main()
<
//массив идентификаторов потоков
pthread_t thr[ SIZE_I + SIZE_J ];
//инициализация исключающей блокировки
pthread_mutex_init(&lock, NULL);
DATA *arg;
// Ввод
for (int i=0;i<SIZE_I; P ++i)<>
<
for (int z=0; z<SIZE_J; P ++z)<>
<
arg = new DATA;
arg->i = i; arg->z = z;
//создаем поток для ввода
pthread_create(&thr[i+z], NULL, input_thr, (void *)arg);
>
>
//Ожидаем завершения всех потоков
//идентификаторы потоков хранятся в массиве
for(int i = 0; i<SIZE_I p ++i)>< SIZE_J; +>
<
pthread_join(thr[i], NULL);
>
//Вычисления
printf("Start calculation\n");
for (int i=0;i<SIZE_I; P ++i)<>
<
for (int z=0; z<SIZE_J; P ++z)<>
<
arg = new DATA;
arg->i = i; arg->z = z; arg->x = S[i][z];
pthread_t thread;
//создаем поток для вычислений
pthread_create(&thread, NULL, thread_f, (void *)arg);
// переводим в отсоединенный режим
pthread_detach(thread);
>
>
do
<
// Основной процесс "засыпает" на 1с
sleep(1);
// Все-ли завершились?
printf("finished %d threads.\n", all);
>while(all<SIZE_I+SIZE_J);
//Печать результатов
for (int i=0;i<SIZE_I; P ++i)<>
<
for (int z=0; z<SIZE_J; P ++z)<>
<
printf("X[%d][%d] = %f\t", i, z, X[i][z]);
>
printf("\n");
>
//Удаляем исключающую блокировку
pthread_mutex_destroy(&lock);
return 0;
>

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

Основной процесс ожидает завершения всех потоков вызовом pthread_join().

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

Для вычислений используются отсоединенные потоки, отсоединение происходит вызовом pthread_detach().

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

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

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

Литература и ссылки

Литература:
1. Теренс Чан "Системное программирование на С++ для Unix"
2. Андрей Робачевский "Операционная система UNIX"

Процесс — это экземпляр запущенной программы. Всякий раз, когда в терминале выполняется какая-нибудь команда (например, команда pwd ), система создает/запускает новый процесс.

Типы процессов

В Linux существует три основных типа процессов:

Как Linux идентифицирует процессы?

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

Родительские процессы — это процессы, которые во время своего выполнения создают другие процессы.

Дочерние процессы — эти процессы, создаваемые другими процессами во время своего выполнения.

Примечание: В любой момент времени в системе не существует двух процессов с одинаковым PID. Вновь создаваемому процессу может быть назначен ранее использованный свободный PID.

Состояния процесса в Linux


Рассмотрим основные состояния процесса:

Выполнение — процесс либо запущен (текущий процесс в системе), либо готов к запуску (ожидает передачи на выполнение процессору).

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

прерываемые ожидающие процессы — могут быть прерваны сигналами;

непрерываемые ожидающие процессы — процессы ожидают непосредственно на аппаратном уровне и не могут быть прерваны каким-либо событием/сигналом.

Завершен — процесс был остановлен, как правило, путем получения сигнала штатного завершения работы exit().

Как получить идентификатор (PID) процесса

Для отображения идентификатора нужного вам процесса можно использовать команду pidof, например:

$ pidof init
$ pidof bash
$ pidof systemd


Примечание: На вышеприведенном скриншоте вы можете видеть, что процессу init назначен PID=1 , а процессу systemd — PID=881 , хотя системой инициализации в Debian является именно systemd. Детально о том, почему возникла такая путаница, читайте здесь.

Чтобы вывести PID и PPID текущей оболочки, выполните:

$ echo $$
$ echo $PPID



Запуск интерактивного процесса в Linux

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



Запуск фонового процесса в Linux

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

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

Чтобы запустить процесс в фоновом режиме, используйте символ & после имени запускаемой программы. В этом случае процесс не будет принимать пользовательский ввод, пока не переместится на передний план:




Отслеживание активных процессов

Существует несколько различных инструментов для просмотра/перечисления запущенных в системе процессов. Двумя традиционными и хорошо известными из них являются команды ps и top:

Команда ps

Отображает информацию об активных процессах в системе, как показано на следующем скриншоте:


Для получения дополнительной информации о процессах, запущенных текущим пользователем, применяется опция -f :


Столбцы, присутствующие в выводе команды ps , имеют следующие значения:

UID — идентификатор пользователя, которому принадлежит процесс (тот, от чьего имени происходит выполнение).

PID — идентификатор процесса.

PPID — идентификатор родительского процесса.

C — загрузка CPU процессом.

STIME — время начала выполнения процесса.

TTY — тип терминала, связанного с процессом.

TIME — количество процессорного времени, потраченного на выполнение процесса.

CMD — команда, запустившая этот процесс.

Также можно отобразить информацию по конкретному процессу, используя команду ps -f [PID] , например:


Есть и другие опции, которые можно использовать вместе с командой ps :

-a — показывает информацию о процессах по всем пользователям;

-x — показывает информацию о процессах без терминалов;

-u — показывает дополнительную информацию о процессе по заданному UID или имени пользователя;

-e — отображение расширенной информации.

Если вы хотите вывести вообще всю информацию по всем процессам системы, то используйте команду ps –aux :


Обратите внимание на выделенный заголовок. Команда ps поддерживает функцию сортировки процессов по соответствующим столбцам. Например, чтобы отсортировать список процессов по потреблению ресурсов процессора (в порядке возрастания), введите команду:

$ ps -aux --sort=%cpu


Если вы ходите выполнить сортировку по потреблению памяти (в порядке убывания), то добавьте к имени интересующего столбца знак минуса:

$ ps -aux --sort=-%mem


Еще один очень популярный пример использования команды ps — это объединение её и команды grep для поиска заданного процесса по его имени:

$ ps -aux | grep bash



Команда top

Команда top отображает информацию о запущенных процессах в режиме реального времени:


PID — идентификатор процесса.

USER — пользователь, которому принадлежит процесс.

PR — приоритет процесса на уровне ядра.

NI — приоритет выполнения процесса от -20 до 19 .

VIRT — общий объем (в килобайтах) виртуальной памяти (физическая память самого процесса; загруженные с диска файлы библиотек; память, совместно используемая с другими процессами и т.п.), используемой задачей в данный момент.

RES — текущий объем (в килобайтах) физической памяти процесса.

SHR — объем совместно используемой с другими процессами памяти.

%CPU — процент используемых ресурсов процессора.

%MEM — процент используемой памяти.

TIME+ — количество процессорного времени, потраченного на выполнение процесса.

COMMAND — имя процесса (команды).

< — процесс с высоким приоритетом;

N — процесс с низким приоритетом;

l — многопоточный процесс;

s — лидер сессии.

Примечание: Все процессы объединены в сессии. Процессы, принадлежащие к одной сессии, определяются общим идентификатором сессии — идентификатором процесса, который создал эту сессию. Лидер сессии — это процесс, идентификатор сессии которого совпадает с его идентификаторами процесса и группы процессов.

Команда glances

Команда glances — это относительно новый инструмент мониторинга системы с расширенными функциями:

Примечание: Если в вашей системе отсутствует данная утилита, то установить её можно с помощью следующих команд:

$ yum install -y glances

$ sudo apt-get update
$ sudo apt-get install glances

Управление процессами в Linux

Также в Linux присутствуют некоторые команды для управления процессами:

kill — посылает процессу сигнал завершения работы;

pkill — завершает процесс по его имени;

pgrep — ищет процесс по его имени (и, опционально, по имени запустившего его пользователя);

killall — завершает все активные процессы.

Ниже приведены несколько основных примеров их использования:

$ pgrep -u diego firefox
$ kill 6516
$ pgrep -u diego firefox
$ pgrep -u diego glances
$ pkill glances
$ pgrep -u diego glances



Отправка сигналов процессам

Основополагающим способом управления процессами в Linux является отправка им соответствующих сигналов. Для перечисления списка всех доступных сигналов, введите команду:


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

SIGHUP (1) — отправляется процессу, когда его управляющий терминал закрыт.

SIGINT (2) — отправляется процессу управляющим терминалом, когда пользователь прерывает процесс нажатием клавиш Ctrl+C.

SIGQUIT (3) — отправляется процессу, если пользователь посылает сигнал выхода Ctrl+D.

SIGKILL (9) — этот сигнал немедленно завершает (убивает) процесс, и процесс не будет выполнять никаких операций очистки за собой.

SIGTERM (15) — сигнал завершения программы (отправляется командой kill по умолчанию).

SIGTSTP (20) — отправляется процессу управляющим терминалом с запросом на остановку; инициируется пользователем нажатием клавиш Ctrl+Z.

Ниже приведены примеры команды kill для уничтожения приложения firefox с помощью PID, после его зависания:

$ kill -SIGKILL 2275

Чтобы убить приложение, используя его имя, применяются команды pkill или killall , например:

Изменение приоритета процесса

В системе Linux все активные процессы имеют определенный приоритет выполнения, задаваемый так называемым nice-значением. Процессы с более высоким приоритетом обычно получают больше процессорного времени, чем процессы с более низким приоритетом. Однако пользователь с root-правами может повлиять на это с помощью команд nice и renice.

Узнать значение приоритета команды можно по выводу команды top (столбец NI):


Используйте команду nice , чтобы задать NI-значение для запускаемого процесса. Имейте в виду, что обычные пользователи могут задавать данный параметр в диапазоне от 0 до 20 тем процессам, которыми они владеют. Только пользователь root может использовать отрицательные значения приоритета.

Чем больше nice-значение, тем меньшим приоритетом будет обладать процесс. Например, вы можете задать приоритет для запускаемого процесса следующим образом:

$ nice -n 10 firefox

Чтобы изменить приоритет уже запущенного процесса, используйте команду renice следующим образом:

$ renice +8 5547
$ renice +8 1151

На данный момент это всё! Если у вас есть какие-либо вопросы или дополнительные идеи, вы можете поделиться ими с нами с помощью комментариев.

Читайте также: