Mainthread что это ubuntu

Обновлено: 04.07.2024

Linux - начинающим. Часть 7. Потоки, перенаправление потоков, конвейер

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

Прежде всего определимся с терминами. Мы часто говорим: "консоль", "терминал", "командная строка" - не сильно задумываясь о смысле этих слов и подразумевая под этим в большинстве своем CLI - интерфейс командной строки. Во многих случаях такое упрощение допустимо и широко используется в профессиональной среде. Но в данном случае точный смысл этих терминов имеет значение для правильного понимания происходящих процессов.

Стандартные потоки

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

linux-standard-stream-pipeline-001.jpg

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

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

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

linux-standard-stream-pipeline-002.jpg

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

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

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

Перенаправление потоков

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

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

linux-standard-stream-pipeline-003.jpg

Но что, если мы хотим сохранить результат работы команды в файл? Нет ничего проще, воспользуемся перенаправлением, для этого следует использовать знак > .

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

linux-standard-stream-pipeline-004.jpg

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

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

Немного изменим последовательность команд:

linux-standard-stream-pipeline-006.jpg

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

Пойдем дальше. Как видим в выводе кроме списка файлов присутствуют строки "итого", нам они не нужны, и мы хотим от них избавиться. В этом нам поможет утилита grep, которая позволяет отфильтровать строки согласно некому выражению. Например, можно сделать так:

linux-standard-stream-pipeline-007.jpg

В целом результат достигнут, но ценой трех команд и наличием одного промежуточного файла. Можно ли сделать проще?

До этого мы перенаправляли поток вывода, но тоже самое можно сделать и с потоком ввода, используя для этого знак < . Например, мы можем сделать так:

Но это ничего не изменит, поэтому мы пойдем другим путем и перенаправим на ввод одной команды вывод другой:

На первый взгляд выглядит несколько сложно, но обратимся к man по grep:

В данном примере весь вывод стандартного потока ошибок будет перенаправлен в пустое устройство /dev/null.

Но можно пойти и другим путем, перенаправив поток ошибок в стандартный поток вывода:

Конвейер

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

Самый простой пример:

Первая команда выведет список всех установленных пакетов, вторая отфильтрует только те, в наименовании которых есть строка "gnome".

linux-standard-stream-pipeline-011.jpg

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

linux-standard-stream-pipeline-012.jpg

Какой из этих способов лучше? Любой, Linux ни в чем не ограничивает пользователей и предоставляет им много путей для решения одной и той же задачи.

Еще один важный момент, если вы повышаете права с помощью команды sudo, то данное повышение прав через конвейер не распространяется. Например, если мы решим выполнить:

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

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


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

Общие сведения

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


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


Ядро задействует копирование при записи для страниц с данными, сегментов памяти родительского процесса содержащие стек и кучу. Вследствие того, что процессы часто выполняют вызов fork и сразу после этого exec , копирование их страниц во время выполнения вызова fork становится ненужной расточительностью — их все равно приходится отбрасывать после выполнения exec . Сперва записи таблицы страниц указывают на одни и те же страницы физической памяти родительского процесса, сами же страницы маркируются только для чтения. Копирование страницы происходит ровно в тот момент, когда требуется ее изменить.

Таблицы страниц до и после изменения общей страницы памяти во время копирования при записи.


Существует закономерность между количеством параллельных нитей исполнения процесса, алгоритмом программы и ростом производительности. Это зависимость называется Законом Амдаля.

Закон Амдаля для распараллеливания процессов.


Используя уравнение, показанное на рисунке, можно вычислить максимальное улучшение производительности системы, использующей N процессоров и фактор F, который указывает, какая часть системы не может быть распараллелена. Например 75% кода запускается параллельно, а 25% — последовательно. В таком случае на двухядерном процессоре будет достигнуто 1.6 кратное ускорение программы, на четырехядерном процессоре — 2.28571 кратное, а предельное значение ускорения при N стремящемся к бесконечности равно 4.

Отображение потоков в режим ядра

Практически все современные ОС — включая Windows, Linux, Mac OS X, и Solaris — поддерживают управление потоками в режиме ядра. Однако потоки могут быть созданы не только в режиме ядра, но и в режиме пользователя. При использовании этого уровня ядро не знает о существовании потоков — все управление потоками реализуется приложением с помощью специальных библиотек. Пользовательские потоки по разному отображаются на потоки в режиме ядра. Всего существует три модели, из которых 1:1 является наиболее часто используемой.

Отображение N:1

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


Отображение 1:1

Это самая проста модель, в которой каждый поток созданный в каком-нибудь процессе непосредственно управляется планировщиком ядра ОС и отображается на один единственный поток в режиме ядра. Чтобы приложение не плодило бесконтрольно потоки, перегружая ОС, вводят ограничение на максимальное количество потоков поддерживаемых в ОС. Данный способ отображения потоков поддерживают ОС Linux и Windows.


Отображение M:N

При таком подходе M пользовательских потоков мультиплексируются в такое же или меньшее N количество потоков ядра. Преодолеваются негативные эффекты двух других моделей: нити по-настоящему исполняются параллельно и нет необходимости в ОС вводить ограничения на их общее количество. Вместе с тем данную модель довольно трудно реализовать с точки зрения программирования.


Потоки POSIX

В конце 1980-х и начале 1990-х было несколько разных API, но в 1995 г. POSIX.1c стандартизовал потоки POSIX, позже это стало частью спецификаций SUSv3. В наше время многоядерные процессоры проникли даже в настольные ПК и смартфоны, так что у большинства машин есть низкоуровневая аппаратная поддержка, позволяющая им одновременно выполнять несколько потоков. В былые времена одновременное исполнение потоков на одноядерных ЦПУ было лишь впечатляюще изобретательной, но очень эффективной иллюзией.

Pthreads определяет набор типов и функций на Си.

  • pthread_t — идентификатор потока;
  • pthread_mutex_t — мютекс;
  • pthread_mutexattr_t — объект атрибутов мютекса
  • pthread_cond_t — условная переменная
  • pthread_condattr_t — объект атрибута условной переменной;
  • pthread_key_t — данные, специфичные для потока;
  • pthread_once_t — контекст контроля динамической инициализации;
  • pthread_attr_t — перечень атрибутов потока.

В традиционном Unix API код последней ошибки errno является глобальной int переменной. Это однако не годится для программ с множественными нитями исполнения. В ситуации, когда вызов функции в одном из исполняемых потоков завершился ошибкой в глобальной переменной errno , может возникнуть состояние гонки из-за того, что и остальные потоки могут в данный момент проверять код ошибки и оконфузиться. В Unix и Linux эту проблему обошли тем, что errno определяется как макрос, задающий для каждой нити собственное изменяемое lvalue .

Из man errno
Переменная errno определена в стандарте ISO C как изменяемое lvalue int и не объявляемая явно; errno может быть и макросом. Переменная errno является локальным значением нити; её изменение в одной нити не влияет на её значение в другой нити.

Создание потока

В начале создается потоковая функция. Затем новый поток создается функцией pthread_create() , объявленной в заголовочном файле pthread.h. Далее, вызывающая сторона продолжает выполнять какие-то свои действия параллельно потоковой функции.

При удачном завершении pthread_create() возвращает код 0, ненулевое значение сигнализирует об ошибке.

  • Первый параметр вызова pthread_create() является адресом для хранения идентификатора создаваемого потока типа pthread_t .
  • Аргумент start является указателем на потоковую void * функцию, принимающей бестиповый указатель в качестве единственной переменной.
  • Аргумент arg — это бестиповый указатель, содержащий аргументы потока. Чаще всего arg указывает на глобальную или динамическую переменную, но если вызываемая функция не требует наличия аргументов, то в качестве arg можно указать NULL .
  • Аргумент attr также является бестиповым указателем атрибутов потока pthread_attr_t . Если этот аргумент равен NULL , то поток создается с атрибутами по умолчанию.

Рассмотрим теперь пример многопоточной программы.

Чтобы подключить библиотеку Pthread к программе, нужно передать компоновщику опцию -lpthread .

О присоединении потока pthread_join расскажу чуть позже. Строка pthread_t tid задает идентификатор потока. Атрибуты функции задает pthread_attr_init(&attr) . Так как мы не задавали их явно, будут использованы значения по умолчанию.

Завершение потока

Поток завершает выполнение задачи когда:

  • потоковая функция выполняет return и возвращает результат произведенных вычислений;
  • в результате вызова завершения исполнения потока pthread_exit() ;
  • в результате вызова отмены потока pthread_cancel() ;
  • одна из нитей совершает вызов exit()
  • основная нить в функции main() выполняет return , и в таком случае все нити процесса резко сворачиваются.

Синтаксис проще, чем при создании потока.

Если в последнем варианте старшая нить из функции main() выполнит pthread_exit() вместо просто exit() или return , то тогда остальные нити продолжат исполняться, как ни в чем не бывало.

Ожидание потока

Функция pthread_join() ожидает завершения потока обозначенного THREAD_ID . Если этот поток к тому времени был уже завершен, то функция немедленно возвращает значение. Смысл функции в том, чтобы синхронизировать потоки. Она объявлена в pthread.h следующим образом:

При удачном завершении pthread_join() возвращает код 0, ненулевое значение сигнализирует об ошибке.

Если указатель DATA отличается от NULL , то туда помещаются данные, возвращаемые потоком через функцию pthread_exit() или через инструкцию return потоковой функции. Несколько потоков не могут ждать завершения одного. Если они пытаются выполнить это, один поток завершается успешно, а все остальные — с ошибкой ESRCH. После завершения pthread_join() , пространство стека связанное с потоком, может быть использовано приложением.

В каком-то смысле pthread_joini() похожа на вызов waitpid() , ожидающую завершения исполнения процесса, но с некоторыми отличиями. Во-первых, все потоки одноранговые, среди них отсутствует иерархический порядок, в то время как процессы образуют дерево и подчинены иерархии родитель — потомок. Поэтому возможно ситуация, когда поток А, породил поток Б, тот в свою очередь заделал В, но затем после вызова функции pthread_join() А будет ожидать завершения В или же наоборот. Во-вторых, нельзя дать указание одному ожидай завершение любого потока, как это возможно с вызовом waitpid(-1, &status, options) . Также невозможно осуществить неблокирующий вызов pthread_join() .

Досрочное завершение потока

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

При удачном завершении pthread_cancel() возвращает код 0, ненулевое значение сигнализирует об ошибке.

Важно понимать, что несмотря на то, что pthread_cancel() возвращается сразу и может завершить поток досрочно, ее нельзя назвать средством принудительного завершения потоков. Дело в том, что поток не только может самостоятельно выбрать момент завершения в ответ на вызов pthread_cancel() , но и вовсе его игнорировать. Вызов функции pthread_cancel() следует рассматривать как запрос на выполнение досрочного завершения потока. Поэтому, если для вас важно, чтобы поток был удален, нужно дождаться его завершения функцией pthread_join() .

Небольшая иллюстрация создания и отмены потока.

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


Как мы видим есть вовсе неотменяемые потоки, а поведением по умолчанию является отложенное завершение, которое происходит в момент завершения. А откуда мы узнаем, что этот самый момент наступил? Для этого существует вспомогательная функция pthread_testcancel .

Отсоединение потока

Любому потоку по умолчанию можно присоединиться вызовом pthread_join() и ожидать его завершения. Однако в некоторых случаях статус завершения потока и возврат значения нам не интересны. Все, что нам надо, это завершить поток и автоматически выгрузить ресурсы обратно в распоряжение ОС. В таких случаях мы обозначаем поток отсоединившимся и используем вызов pthread_detach() .

При удачном завершении pthread_detach() возвращает код 0, ненулевое значение сигнализирует об ошибке.

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

Потоки versus процессы

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

В начальной части статьи мы уже указывали на эти преимущество, поэтому вкратце их просто перечислим.

  • Потоки довольно просто обмениваются данными по сравнению с процессами.
  • Создавать потоки для ОС проще и быстрее, чем создавать процессы.

Теперь немного о недостатках.

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

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


23 апреля состоялся релиз Ubuntu версии 20.04 с кодовым названием Focal Fossa, являющимся следующим выпуском Ubuntu для долгосрочной поддержки (LTS) и является продолжением Ubuntu 18.04 LTS, выпущенной в 2018 году.

Немного про кодовое имя. Слово «Focal» означает «центральная точка» или «самая важная часть», то есть связано с понятием средоточия, центром каких-либо свойств, явлений, событий, а «Fossa» имеет корень «FOSS» (Free and Open-Source Software — свободное и открытое программное обеспечение) и по традиции именования версий Ubuntu названиями животных означает Фосса — самое крупное хищное млекопитающее из семейства виверровых с острова Мадагаскар.

Разработчики позиционируют Ubuntu 20.04 как важное и успешное обновление с поддержкой в течение следующих 5 лет для настольных компьютеров и серверов.

Ubuntu 20.04 явилась логическим продолжением Ubuntu 19.04 «Disco Dingo» и Ubuntu 19.10 «Eoan Ermine». В версиях для настольных компьютеров, следуя последним тенденциям, появилась темная тема. Таким образом, в Ubuntu 20.04 есть три варианта стандартной темы Yaru:

Ключевые изменения

Ubuntu 20.04 основана на ядре 5.4, которое вышло в свет 24 ноября 2019 года. В этой версии были реализованы несколько важных нововведений, о которых мы расскажем ниже.

Инженеры Canonical провели тестирование различных алгоритмов сжатия для ядра и начального загрузочного образа initramfs, пытаясь найти компромисс между наилучшим сжатием (меньшим размером файла) и временем распаковки. Алгоритм сжатия без потерь lz4 показал наиболее заметные результаты и был добавлен в Ubuntu 19.10, что позволило ей сократить время загрузки по сравнению с предыдущими выпусками (Ubuntu 18.04 и 19.04). Этот же алгоритм сохранится в Ubuntu 20.04.

Linux Lockdown Kernel

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

exFAT

Файловая система Microsoft FAT не позволяет передавать файлы размером более 4 ГБ. Чтобы преодолеть это ограничение, Microsoft создала файловую систему exFAT (от англ. Extended FAT — «расширенная FAT»). Теперь вы можете отформатировать, например, USB-накопитель в exFAT при помощи встроенной поддержки файловой системы exFAT.

WireGuard

Хотя Ubuntu 20.04 не будет использовать ядро 5.6, по крайней мере сразу, она уже сейчас использует бэкпорт WireGuard в ядре 5.4. WireGuard — это новое слово в индустрии VPN, поэтому включение WireGuard в ядро уже сейчас дает преимущество Ubuntu 20.04 в облачном направлении.

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

Использование Kubernetes

Canonical реализовала в Ubuntu 20.04 полную поддержку Кubernetes 1.18 с поддержкой Charmed Kubernetes, MicroK8s и kubeadm.

Установка Kubectl в Ubuntu 20.04:

Использование SNAP

Canonical продолжает продвигать универсальный формат пакета — snap. Это еще более очевидно в выпуске Ubuntu 20.04. Если попытаетесь запустить программу, которая не установлена, то в первую очередь ее предложат установить при помощи:


Улучшенная поддержка ZFS

Хотя Линусу Торвальдсу может не нравиться ZFS, она все еще остается популярной файловой системой и добавлена её экспериментальная поддержка с Ubuntu 19.10.
Она достаточно удобна и стабильна для хранения данных, тот же домашний архив или же серверное хранилище на работе («из коробки» умеет больше, чем тот же LVM). ZFS поддерживает размеры разделов до 256 квадриллионов Зеттабайт (отсюда буква «Z» в наименовании) и может обрабатывать файлы размером до 16 Эксабайт.

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

ZFS присваивает контрольную сумму каждому файлу на диске и постоянно проверяет его состояние по ней. Если она обнаружит, что файл поврежден, то попытается автоматически восстановить его. В программе установки Ubuntu появился отдельный пункт, который позволяет использовать ZFS. Более подробнее с историей ZFS и ее особенностями можете ознакомиться в блоге It's FOSS.

Прощай Python 2.X

Третья версия Python была представлена еще в 2008 году, но даже 12 лет оказалось недостаточно для того, чтобы проекты на Python 2 адаптировать к ней.
Еще в Ubuntu 15.10 была сделана попытка отказаться от Python 2, но его поддержка продолжилась. И сейчас 20 апреля 2020 года вышел Python 2.7.18, который является последним выпуском ветки Python 2. Обновлений для него больше не будет.

Ubuntu 20.04 больше не поддерживает Python 2 и использует Python 3.8 в качестве версии Python по-умолчанию. К сожалению, в мире осталось много проектов, работающих с Python 2, и для них переход на Ubuntu 20.04 может оказаться болезненным.

Последнюю версию Python 2 можете поставить одной командой:


Помимо Python 3.8, разработчики могут оценить обновленный набор инструментов, который включает:

  • MySQL 8,
  • glibc 2.31,
  • OpenJDK 11,
  • PHP 7.4,
  • Perl 5.30,
  • Golang 1.14.

Прощайте 32 бита

Уже несколько лет Ubuntu не предоставляет ISO-образы для 32-битных компьютеров. Сейчас существующие пользователи 32-битных версий Ubuntu могут перейти на Ubuntu 18.04, но до Ubuntu 20.04 обновиться уже не получится. То есть, если сейчас используете 32-битную Ubuntu 18.04, то сможете оставаться с ней до апреля 2023 года.

Как обновиться

Обновиться до Ubuntu 20.04 c предыдущих версий проще простого — достаточно выполнить следующие команды:


Мануал

Процесс создается в памяти при запуске программы или команды.

Ему присваивается уникальный идентификационный номер, известный как идентификатор процесса (PID), который используется ядром для управления процессом до завершения программы или команды, с которой он связан.

Например, когда пользователь входит в систему, запускается оболочка (которая является процессом).

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

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

Эти фоновые системные процессы называются демонами и являются критическими для функциональности системы.

Просмотр процессов

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

Это ps (process status) и top.

Команда ps без каких-либо опций или аргументов выводит список процессов, характерных для терминала, на котором запущена эта команда:

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

Две опции -e (every) и -f (full) часто используются для получения подробной информации о каждом процессе, запущенном в системе.

Существует ряд дополнительных опций, доступных в команде ps.

Подробную информацию можно найти на страницах руководства.


Вывод показывает более подробную информацию о запущенных процессах.

В таблице ниже описан тип содержимого каждого столбца.

Заголовок Описание
UID Идентификатор пользователя владельца процесса.
PID Идентификатор процесса.
PPID Идентификатор продительского процесса.
C Приоритет процесса.
STIME Время старта процесса.
TTY Терминал, на котором был запущен процесс. Console представляет системную консоль, а ? указывает на то, что процесс является демоном.
TIME Общее время выполнения процесса.
CMD Имя команды или программы.

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

Также обратите внимание на номера PID и PPID.

Чем меньше номер процесса, тем раньше он запускается.

Процесс с PID 0 запускается первым при загрузке системы, за ним следует процесс с PID 1, и так далее.

Каждый PID имеет соответствующий PPID в третьем столбце.

Владелец каждого процесса также отображается вместе с именем команды или программы.

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

Ниже показан пример вывода данных из запущенной сессии top:


Нажмите q или Ctrl+c, чтобы выйти из top.

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

Вывод списка определенного процесса

Команду pidof можно использовать для перечисления PID определенного процесса, если вы знаете его имя.

Например, чтобы перечислить PID демона crond, выполните команду следующим образом:

Определение процессов по владению

Процессы можно перечислить по их владению или принадлежности к группе.

Для этого используется команда pgrep.

Например, чтобы перечислить все процессы, принадлежащие root, используйте любую из следующих команд:

Первая команда перечисляет PID, TTY, Time и имя процесса для всех запущенных процессов, принадлежащих пользователю root, в то время как команда pgrep перечисляет только PID.

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

Пример: Вывести список всех процессов, принадлежащих пользователю itsecforu

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

После того как процесс порожден, он не работает непрерывно.

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

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

  • Running определяет, что процесс в данный момент выполняется системным процессором.
  • Sleeping состояние показывает, что процесс в настоящее время ожидает ввода от пользователя или другого процесса.
  • Waiting означает, что процесс получил входные данные, которых он ждал, и теперь он готов к выполнению, как только придет его очередь.
  • Stopped означает, что процесс остановлен и не будет выполняться, даже когда придет его очередь, если ему не будет послан сигнал.
  • Состояние zombie означает, что процесс мертв. Зомби-процесс существует в таблице процессов так же, как и любая другая запись процесса, но не занимает никаких ресурсов. Запись для зомби-процесса сохраняется до тех пор, пока родительский процесс не разрешит ему умереть. Зомби-процесс также называют неработающим процессом.

Приоритет процесса и как его установить

Приоритет процесса (niceness) определяется с помощью значения nice.

Система присваивает значение nice процессу при инициации, чтобы установить приоритет.

Большинство запущенных системных процессов используют значение nice по умолчанию 0.

Дочерний процесс наследует значение nice своего родительского процесса.

Используйте команду ps и укажите опцию -l, чтобы определить niceness запущенных процессов.

Чтобы определить niceness по умолчанию, используйте команду nice без каких-либо опций или аргументов:

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

Например, для запуска команды top с более низким приоритетом +2:

Используйте команду ps с опцией -l или просмотрите вывод команды top и проверьте приоритет процесса.

Она должен быть равен +2.

Чтобы запустить ту же программу на более высоком приоритете с niceness -2, укажите значение через тире:

Проверьте новое значение с помощью команды ps или просмотрите вывод команды top.

Оно должно быть равно -2.

Перечисление открытых файлов

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

Для определения информации о том, какие файлы открыты, какие процессы их используют и кто их владельцы, используется команда lsof (list open files).

Без каких-либо опций эта команда выводит список всех открытых файлов.

Команда создала девять колонок в выходных данных; они перечислены и объяснены в таблице ниже:

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