Создание процессов и исполнение программ. Часть 2
Создание процессов и исполнение программ. Часть 1.
Цель работы:
В данной работе показан порядок создания, завершения и управления дочерними процессами. В действительности, в данный процесс вовлечены три связанных операции: создание дочернего процесса, загрузка и исполнение новым процессом некоторой программы, а так же координация завершения дочернего процесса с главным процессом.
Задание
1. Поясните сколько процессов будет создано следующей программой:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int i;
for(i = 0; i <3; i++)
{
pid_t pid = fork();
printf("I am process %d, My parent is %d\n", getpid(), getppid());
}
В ходе программы будет создано 7 дочерних процессов.
Р | Д1 | Д2 | Д11 | |
i=0 | Д1 | - | - | - |
i=1 | Д2 | Д11 | - | - |
i=2 | Д3 | Д12 | Д21 | Д111 |
2.Создайте текстовый файл с помощь команды
% (echo 'План номер 1'; echo 'План номер 2') > plan.txt
Скомпилируйте и запустите следующую программу:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(){
FILE *fp;
char str[80];
fp = fopen("plan.txt", "r");
if(fp == NULL)
{
fprintf(stderr, "Could not open file");
exit(1);
}
fgets(str, 80, fp);
printf("Parent reads: %s\n", str);
if(fork() == 0)
{
fgets(str, 80, fp);
printf("Child Reads: %s\n", str);
}
fclose(fp);
}
Объясните почему дочерний может считывать файл, открытый родительским процессом?
Дочерний может считывать файл, открытый родительским процессом т.к.
когда выполняется разветвление – fork, все что есть в родительском процессе
копируется в дочерний.
Измените программу таким образом, чтобы файл открывался на запись и дочерний и родительский процессы записывали в него строку «Строка от дочернего процесса» и «Строка от родительского процесса» соответственно.
Измененная программа:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
FILE *fp;
fp = fopen("plan.txt","w");
if(fp == NULL)
{
fprintf(stderr,"Could not open file");
exit(1);
}
fprintf(fp,"Строка от родительского процесса\n");
if(!fork())
{
fprintf(fp,"Строка от дочернего процесса\n");
}
fclose(fp);
}
2. Напишите программу, которая бы производила следующее дерево процессов, где корень представляет родительский процесс. Для каждого процесса выводите его собственный и родительский идентификаторы.
Код программы:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int pid_1;
int pid_11;
int pid_12;
int pid_2;
int pid_21;
int pid_22;
int status;
pid_1=fork();
if (pid_1== 0)
{
pid_11=fork();
if(pid_11==0)
printf("I am the second generation child process - %d. My parent is - %d\n", getpid(), getppid()); // выполняет дочерний дочернего процесса
else
{
wait(&status);
pid_12=fork();
if(pid_12==0)
printf("I am the second generation child process - %d. My parent is - %d\n",getpid(),getppid());// выполняет дочерний дочернего процесса
else
{
wait(&status);
printf("I am the first generation child process - %d. My parent is - %d\n",getpid(),getppid()); // выполняет дочерний родительского процесса
}
}
}
else
{
wait(&status);
pid_2=fork();
if(pid_2==0)
{
pid_21=fork();
if(pid_21==0)
printf("I am the second generation child process - %d. My parent is - %d\n",getpid(),getppid());// выполняет дочерний дочернего процесса
else
{
wait(&status);
pid_22=fork();
if(pid_22==0)
printf("I am the second generation child process - %d. My parent is - %d\n",getpid(),getppid()); // выполняет дочерний дочернего процесса
else
{
wait(&status);
printf("I am the first generation child process - %d. My parent is - %d\n",getpid(),getppid()); // выполняет дочерний родительского процесса
}
}
}
else
{
wait(&status);
printf("I am the parent process - %d.\n",getpid()); // выполняет родительский процесс
}
}
}
Результат выполнения программы:
I am the second generation child process - 4083. My parent is - 4082
I am the second generation child process - 4084. My parent is - 4082
I am the first generation child process - 4082. My parent is - 4081
I am the second generation child process - 4086. My parent is - 4085
I am the second generation child process - 4087. My parent is - 4085
I am the first generation child process - 4085. My parent is - 4081
I am the parent process - 4081.
Создание процессов и исполнение программ. Часть 2.
Цель работы:
В данной работе показано как программа может заменить свой код на код из другого исполняемого файла. В действительности, в данный процесс вовлечены три связанных операции: создание дочернего процесса, загрузка и исполнение новым процессом некоторой программы, а так же координация завершения дочернего процесса с главным процессом.
Задание.
1. Напишите программу, создающую дочерний процесс для исполнения команды. Программа должна выводить:
• идентификатор родительского процесса.
• идентификатор дочернего процесса и результат функции fork– в контексте
родительского процесса
• идентификатор дочернего – в контексте дочернего
• сообщения об ошибке, если exec завершится неудачно.
В случае ошибки exec вызывайте exit(1)
Код программы:
Файл exc21_1.с
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int pid=fork();
if(pid==0)
{
execv("exc21_2.ou",NULL);
printf ("EXEC Failed\n");
_exit(1);
}
else
printf("Parent id=%d and child id=%d\n",getpid(),pid);
}
Файл exc21_2.с
#include <stdio.h>
int main(void)
{
printf("Child id=%d\n",getpid());
}
Результат выполнения программы:
Parent id=4566 and child id=4567
Child id=4567
2. Напишите программу, которая создает 2 дочерних процесса и ждет их завершения и по-разному реагирует на их завершение. Выводите сообщения о ходе выполнения программы и ошибках. При завершении дочернего вызывайте exit
Файл exc22_1.с
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
int status;
if(!fork())
{
execv("exc22_2.ou", NULL);
printf ("EXEC Failed\n");
_exit(1);
}
else
{
wait(&status);
printf("First child end\n");
if(!fork())
{
execv("exc22_3.ou", NULL);
printf ("EXEC Failed\n");
_exit(1);
}
else
{
wait(&status);
printf("Second child end\n");
}
}
}
Файл exc22_2.с
#include <stdio.h>
int main(void)
{
printf("Hello! I am first child\n");
}
Файл exc22_3.с
#include <stdio.h>
int main(void)
{
printf("Hello! I am second child\n");
}
Результат выполнения программы:
Hello! I am first child
First child end
Hello! I am second child
Second child end
3. Напишите оболочку – программу, ожидающую ввод команды и выполняющая ее в дочернем процессе.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char * argv[])
{
int pid, status;
if (argc < 2)
{
printf("Usage: %s command, [arg1 [arg2]...]\n", argv[0]);
return EXIT_FAILURE;
}
printf("Starting %s...\n", argv[1]);
pid = fork();
if (pid == 0)
{
execvp(argv[1], &argv[1]);
perror("execvp");
return EXIT_FAILURE; // Never get there normally
}
else
{
if (wait(&status) == -1)
{
perror("wait");
return EXIT_FAILURE;
}
if (WIFEXITED(status))
printf("Child terminated normally with exit code %i\n", WEXITSTATUS(status));
if (WIFSIGNALED(status))
printf("Child was terminated by a signal #%i\n", WTERMSIG(status));
if (WCOREDUMP(status))
printf("Child dumped core\n");
if (WIFSTOPPED(status))
printf("Child was stopped by a signal #%i\n", WSTOPSIG(status));
}
return EXIT_SUCCESS;
}
Результат выполнения программы:
user:~$ ./exec.ou ps
Starting ps...
PID TTY TIME CMD
2020 pts/1 00:00:00 bash
4919 pts/1 00:00:00 exec.ou
4920 pts/1 00:00:00 ps
Child terminated normally with exit code 0
Заключение: Мы научились создавать дочерние процессы, создавать программу, которая заменяет свой код на код из другого исполняемого файла.