Аргументы командной строки

Содержание

1. Введение------------------------------------------------------------------------------------- стр 3
2. Цели------------------------------------------------------------------------------------------ стр 4
3. Задачи---------------------------------------------------------------------------------------- стр 5
4. Задание--------------------------------------------------------------------------------------- стр 6
5. Код решений-------------------------------------------------------------------------------- стр 7
6. Блок схема алгоритма--------------------------------------------------------------------- стр 10
7. Скриншоты работ-------------------------------------------------------------------------- стр 14
8. Описание программ----------------------------------------------------------------------- стр 15
9. Теоретическая часть----------------------------------------------------------------------- стр 16
10. Вывод---------------------------------------------------------------------------------------- стр 18
11. Список литературы------------------------------------------------------------------------ стр 18

 


 

Введение

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

У каждого процесса есть уникальный номер, называемый process ID, или PID, и, как и у файлов, у каждого процесса есть владелец и группа. Информация о владельце и группе процесса используется для определения того, какие файлы и устройства могут быть открыты процессом с учетом прав на файлы, о которых говорилось ранее. Также у большинства процессов есть родительский процесс. Например, при запуске команд из оболочки, оболочка является процессом и любая запущенная команда также является процессом. Для каждого запущенного таким путем процесса оболочка будет являться родительским процессом. Исключением из этого правила является специальный процесс, называемый init. init всегда первый процесс, его PID всегда равен 1. init запускается автоматически ядром во время загрузки.

В курсовой работе мы изучим работу с процессами и запуск других программ из своей.

Цели

Целью данной лабораторной работы является практическое изучение создания процессов с одинаковой и различной логикой работы с помощью fork(), просмотр идетификаторов процесса нынешнего и процесса родительского. Так же просмотр аргументов командной строки и параметров системы. И порождение программ из своей с помощью одной из функций семейства exec(). Программы должны быть написаны, скомпилированы и запущены в UNIX подобной системе.

 

 

Задачи

Первая задача заключается в создании процесса в UNIX и использование системного вызова fork().

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

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

Четвертая задача дает возможность использования системного вызовы exec() для прогона программ.

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

Задание

Задание 1. Набрать представленную программ, скомпилировать ее и запустить. Проанализировать полученный результат.

Задание 2. Изменить программу из задания 1 так, чтобы родитель и ребенок совершали разные действия.

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

Задание 4. Откомпилировать и запустить представленную программу. Проанализировать результат.

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

Код решения

Задание1.

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

 

int main(){

pid_t pid, ppid;

int a = 0;

(void)fork(); // создаем два одинаковых процесса

a = a+1; // изменяем значение переменной

pid = getpid(); // получаем pid нынешнего процесса

ppid = getppid(); // получаем pid родительского процесса

printf("My pid = %d, my ppid = %d, result = %d\n", (int)pid, (int)ppid, a); // выводим все найденные значения и видим, что значение a изменилось только на единицу в каждом из процессов

return 0;

}

 

Задание 2.

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

 

int main(){

pid_t pid, ppid;

pid = fork(); // создаем два одинаковых процесса

if(pid == -1){ // если не получилось создать процесс

printf("\nError!!!");

} else if(pid == 0){ // если мы находимся в процессе ребенка

printf("I'm child!\n");

} else { // если мы находимся в процессе родителя

printf("I'm you father!\n");

}

return 0;

}

 

Задание 3.

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

 

int main(int argc, char *argv[], char *envp[]){

printf("Аргументы командной строки: \n");

int i = 0;

for(; i < argc; i++){ // проходим по всем аргументам командной строки

printf("%s ",argv[i]); // выводим каждый аргумент

}

printf("\nПераметры окружающей среды: \n");

i = 0;

while(envp[i] != NULL){ // идем пока не встретим NULL в параметрах

printf("%s\n",envp[i]); // выводим каждый параметр

i++;

}

return 0;

}

 

Задание 4.

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[], char *envp[]){

(void)execle("/bin/cat","/bin/cat","03-2.c",NULL,envp); // запускаем программ cat с параметрами "имя программы" и "имя файла"

printf("Error!"); // если не получилось запустить программу, то наша программа пойдет дальше по коду и выдаст ошибку

exit(-1);

return 0;

}

 

Задание 5.

#include <sys/types.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

 

int main(int argc, char *argv[], char *envp[]){

pid_t pid;

pid = fork(); // создаем два одинаковых процесса

if(pid == -1){ // если ошибка

printf("\nError!!!");

} else if(pid == 0){ // если находимся в дочернем потоке

execle("/bin/ls","-l",NULL,envp); // запускаем ls с параментром -l для отображения всех файлов в директории

} else { // если находимся в родительском потоке

wait(); // ожидаем завершение дочернего потока

printf("I'm you father!\n");

}

return 0;

}

 

 

Блок-схема алгоритма

Задание1.

 

 

Задание 2.

 

 

Задание 3.

Задание 4.

 

Задание 5.

 

 

Скриншоты работы

Задание 1.

Задание 2.

 

Задание 3.

 

Задание 4.

 

Задание 5.

Описание программ

Задание 1.

Была написана программа с использованием fork() для порождения аналогичного процесса. На примере объявления переменной a мы видим, что у процессов при одинаковом имени переменной разные участки памяти. После изменения значения переменной в каждом из процессов мы получаем идентификатор нынешнего процесса и процессам родителя. При выводе результата мы видим, что один из процессов является дочерним для другого, а второй является дочерним для процесса консоли.

Задание 2.

Так же была написана программа с использованием fork(), но с анализом возвращаемого значения. Так, если он вернул -1, то это означает, что процесс не создался, если вернулся 0, то процесс удачно создан и далее происходит работа дочернего процесса, если же вернулось другое значение, то это означает, что мы работаем в родительском процессе. Каждый из процессов в данной программе выполняет различные действия.

Задание 3.

Была написана программа, которая выводим все аргументы командной строки, которые хранятся в принимаемом main-ом вторым параметром массиве *argv, а их количество храниться в переменной argc, которая является первым параметром main(). А так же в программе присутствует вывод всех параметров окружающей среды процесса. Это параметры хранятся в массиве *envp, который является третьим параметром main(). Данный массив заканчивается NULL, что является удобным при прохождении по массиву с помощью while().

Задание 4.

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

Задание 5.

Для обобщений знаний по заданиям была написана программа, которая запускает одинаковые процессы с помощью fork() и один из них (дочерний) заменяет на указанную нами программу (“ls -l”). Данный способ дает возможность не теряя свою программу запускать другую.

 

 

Теоретическая часть

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

У каждого процесса есть уникальный номер, называемый process ID, или PID, и, как и у файлов, у каждого процесса есть владелец и группа. Информация о владельце и группе процесса используется для определения того, какие файлы и устройства могут быть открыты процессом с учетом прав на файлы, о которых говорилось ранее. Также у большинства процессов есть родительский процесс. Например, при запуске команд из оболочки, оболочка является процессом и любая запущенная команда также является процессом. Для каждого запущенного таким путем процесса оболочка будет являться родительским процессом. Исключением из этого правила является специальный процесс, называемый init. init всегда первый процесс, его PID всегда равен 1. init запускается автоматически ядром во время загрузки.

Для запуска программ в UNIX используются два системных вызова – fork() и exec().

fork() — системный вызов, создающий новый (дочерний) процесс, идентичный выполняющему этот вызов. После вызова fork() алгоритм обычно разветвляется (родительский процесс получает от fork() значение PID дочернего процесса, а дочерний получает нуль).

После fork() дочерний процесс чаще всего выполняет системный вызов exec(), загружающий в пространство процесса новую программу (именно так, и только так, в UNIX выполняется запуск программы в отдельном процессе). Так, первый (нулевой) процесс UNIX (ядро системы) создаёт свою копию, чтобы запустить init (процесс с PID = 1), который в свою очередь создаёт дочерние процессы для запуска инициализации системы и терминалов.

При завершении работы программа (дочерний процесс) выполняет системный вызов exit(), при этом родительский процесс с помощью системного вызова wait() (или waitpid()) должен очистить таблицы планировщика процессов от информации о своем дочернем процессе. Если этого не происходит и родительский процесс завершается, не вызвав wait() для всех своих дочерних процессов, в системе возникают зомби (zombie), представляющие собой записи в таблицах планировщика процессов. Очистить операционную систему от зомби можно только с помощью перезагрузки.

Аргументы командной строки.

Иногда при запуске программы бывает полезно передать ей какую-либо информацию. Обычно такая информация передается функции main() с помощью аргументов командной строки. Аргумент командной строки — это информация, которая вводится в командной строке операционной системы вслед за именем программы. Имя программы представляет собой аргумент командной строки, он указывает имя той программы, которую вы собираетесь компилировать. Чтобы принять аргументы командной строки, используются два специальных встроенных аргумента: argc и argv. Параметр argc содержит количество аргументов в командной строке и является целым числом, причем он всегда не меньше 1, потому что первым аргументом считается имя программы. А параметр argv является указателем на массив указателей на строки. В этом массиве каждый элемент указывает на какой-либо аргумент командной строки. Все аргументы командной строки являются строковыми, поэтому преобразование каких бы то ни было чисел в нужный двоичный формат должно быть предусмотрено в программе при ее разработке.

 

Вывод

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

 

 

Литература

1. Лав Р. Linux. Системное программирование.–СПб.: Питер, 2008.– 416 с.