Создание процессов и исполнение программ. Часть 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

 

 

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