У меня проблемы с пониманием каналов и их реализацией в xv6

Я изучаю операционные системы самостоятельно из лекций MOOC, доступных онлайн, и хотел работать на xv6. Я читал документацию по xv6, и в главе 0, когда речь идет о каналах (стр. 13), у меня есть сомнения.

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;

pipe(p);
if(fork()==0){
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
exec("/bin/wc", argv);
}
else{
write(p[1], "hello world\n", 12);
close(p[0]);
close(p[1]);}

Написано что:
Теперь дочерний элемент возвращает конец чтения в файловый дескриптор 0, закрывает fds в p и исполняет wc. Когда wc читает из стандартного ввода, он читает из канала. Родитель пишет в конец записи канала, а затем закрывает оба своих файловых дескриптора.

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

Теперь я пишу в родительском процессе, и если child достигает exec до того, как parent заканчивает запись в p[1], child будет ждать, а после того, как он закончит запись, child будет читать из p[0] и будет выполнять exec. Итак, правильно ли говорить, что существуют специальные привилегии для каналов, которые заставляют их поддерживать межпроцессное взаимодействие посредством совместного использования каналов? Таким образом, в отличие от переменных, чьи изменения не будут отражаться в другом процессе, каналы являются общими, и, следовательно, их изменения отражаются друг в друге?
Правильно ли приведенные выше рассуждения?

1 ответ

Решение

Ваши рассуждения в основном правильные. Не то чтобы трубы имели особые привилегии; ты просто думаешь о них как о неправильной вещи. Канал не является переменной, это объект ОС, созданный в ядре с использованием pipe системный вызов и может быть открыт в одном или нескольких процессах одновременно. Данные записываются в конец канала для записи (то есть второй из двух файловых дескрипторов, созданных в pipe(p) вызвать и сохранить в массиве p) читается в другом файловом дескрипторе (p[0] здесь, который затем дублируется на дескриптор файла 0, который является дескриптором файла, используемого для stdin). Это чтение и запись в канал возможны независимо от того, в каких процессах открыты эти файловые дескрипторы.

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

Создание каналов вручную обычно выполняется для межпроцессного взаимодействия, но не обязательно в исходном коде. Кроме того, обе программы не должны быть запущены одновременно. Если вы пишете строку в оболочке, используя | ("символ трубы"), вы говорите оболочке создать трубу из stdout первой команды в stdin второй команды (так же, как ваш пример выше создает канал в stdin из /bin/wc). То есть команда оболочки вроде ls | wc) создает канал с доступным для записи концом, заданным как дескриптор файла 1 (stdout), выполняет ls и, таким образом, захватывает свои выходные данные в этом канале, затем устанавливает читаемый конец как дескриптор файла 0 (stdin) и выполняет wc, который должным образом читает вывод теперь законченного ls и выводит результат в свой stdout, который заканчивается на вашем терминале.

Другие вопросы по тегам