Небольшой персонаж оболочки, внутренняя реализация действительно не проста!

задняя часть WeChat Командная строка Shell
Небольшой персонаж оболочки, внутренняя реализация действительно не проста!

Мы часто используем конвейерные команды для импорта вывода одной инструкции во ввод другой инструкции, то есть прикладом к устам, этот принцип известен даже учащимся начальной школы. Но если вы хотите подробно спросить, как вывод одной инструкции импортируется во ввод другой инструкции и какую роль играет конвейер, по оценкам, менее 1% людей могут ответить на этот вопрос. Теперь давайте подробно проанализируем принцип реализации инструкции конвейера.Что делает оболочка для следующей инструкции?

$ cmd1 | cmd2

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

图片

На рисунке выше мы видим отношения родитель-потомок таблицы дескрипторов процессов, каналов и процессов.

вилка и выполнение

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

$ cmd

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

$ cmd1 | cmd2

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

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

pipe

Пайпы используются для связи между родительским и дочерним процессами.Пайпы создаются до форка, а пайп станет связующим звеном между родительским и дочерним процессами после форка. Функция pipe возвращает два дескриптора (pipe_in, pipe_out), один для чтения и один для записи.

dup2

Далее нам нужно настроить верхушку дескриптора на рисунке, указать дескриптор stdout процесса cmd1 на канал для записи, а дескриптор stdin процесса cmd2 указать на канал для чтения, что требует волшебного Функция dup2(fd1, fd2), ее функция состоит в том, чтобы связать дескриптор fd1 с объектом ядра, на который указывает fd2.Счетчик ссылок объекта ядра, на который указывает fd1, уменьшается на единицу, и если он уменьшается до нуля, он будет уничтожен. Обратите внимание, что обычно мы вызываем метод close, существенно уменьшая счетчик ссылок, и один и тот же объект ядра может совместно использоваться несколькими процессами. Он официально закрывается, когда счетчик ссылок падает до нуля.

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

Затем закройте ненужные дескрипторы и получите финальную картинку ниже, идеально!

Если это два символа канала и три команды выглядят следующим образом, будут сгенерированы два канала.

$ cmd1 | cmd2 | cmd3

Что произойдет, если процесс на любом конце внезапно зависнет?

Предполагая, что cmd1 зависает первым, конвейер пассивно закрывается, а cmd2 встречает EOF при чтении содержимого конвейера, а затем завершается нормально. Предполагая, что cmd2 зависает первым, канал чтения пассивно закрывается, а cmd1 продолжает запись в канал.В это время процесс получает сигнал SIGPIPE, и по умолчанию процесс завершается напрямую.

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

Прочтите более подробные технические статьи, отсканируйте приведенный выше QR-код и подпишитесь на общедоступную учетную запись WeChat «Code Cave».