Практические занятия 5-7.




 

При организации взаимодействия процессов необходимо рассмотреть три аспекта:

· Возможность одному процессу активизировать или прекратить другой процесс;

· Возможность передать информацию от одного к другому процессу;

· Возможность синхронизировать работу двух и более процессов.

 

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

Int fork(viod)

При ее выполнении операционная система как бы раздваивает процесс, из которого произошло обращение. Вновь созданный процесс-копия наследует не только созданные в головном процессе-родителе дескрипторы файлов, очередей сообщений, семафоров и прочих объектов, но и состояние памяти родительского процесса на момент выполнения вызова fork.

Принципиальное отличие в отношении операционной системы к двум процессам: родительскому и потомку будет заключаться в возвращаемом процедурой fork значением. Процесс-родитель получит в качестве возвращаемого значения идентификатор процесса-потомка, созданного системным вызовом fork. Вновь созданный процесс получит в качестве результата нулевое значение.

Если по той или иной причине новый процесс не был создан, операционная система возвратит в качестве результата системного вызова значение -1.

 

#include <stdio.h>

 

void main()

{

int k,n,Child_id[2],pid;

// обеспечить прямой вывод без буферизации

setvbuf(stdout,(char*)NULL,_IONBF,0);

 

for (n=0;n<2;n++)

{

switch (Child_id[n] = fork())

{

case 0: // процесс - потомок

 

printf("Start of Child: %d \n",n + 1);

 

exit(1);

case -1: // ошибка создания процесса

printf("fork ERROR\n");

exit(7);

}// end of switch

}// end of for

// процесс - родитель

printf("Parent cuntinuation\n");

printf("Two created processes: %d and %d\n", Child_id[0], Child_id[1]);

// ждать завершения процессов - потомков

 

pid=wait(&k);

printf("Parent received end of %d with %d: %d status\n",pid,k>>8,k);

pid=wait(&k);

printf("Parent received end of %d with %d: %d status\n",pid,k>>8,k);

printf("Parent process is finished\n");

} // end of main procedure

 

Пример 1 Использование системного вызова fork

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

Start of Child: 2

или

 

Start of Child: 1

Цифровой код будет зависеть от значения переменной n, унаследованного в процесс потомок. Первый рожденный процесс унаследует нулевое значение этой переменной и соответственно распечатает n + 1 значение равное 1. Второй потомок будет получен расщеплением родительского процесса, когда значение переменной n за счет выполнения операции n++ увеличилось и соответственно в его сообщении будет распечатана цифра 2.

Заметим, что в данном примере еще одна область памяти будет различать состояние процессов. Речь идет о переменных Child_id[0] и Child_id[1]. Процесс-родитель накапливает в этих переменных (элементах массива) идентификаторы порожденных процессов.

Первый процесс-потомок будет иметь нулевое значение Child_id[0] и, строго говоря, неопределенное значение Child_id[1]. Зато второй потомок унаследует от родителя информацию об идентификаторе первого потомка в нулевом элементе массива Child_id[1] а в Child_id[1] получит нулевое значение, как результат системного вызова fork.

В конце приведенной в примере программы производятся действия связанные с очисткой системных областей от завершенных процессов-потомков. Для этого в программе используется процедура (системный вызов) wait.

int wait(int* status)

 

Эта процедура возвращает в процесс-родитель идентификатор завершенного процесса-потомка, а в область параметра вызова процедуры помещается код статуса завершенного процесса. Младший байт этого кода формируется непосредственно операционной системой. Если процесс закончился естественным путем (через системный вызов exit), то значение младшего байта нулевое, а старший байт содержит сформированный системным вызовом exit код возврата завершившегося процесса-потомка.

В нашем случае распечатанный код статуса будет равен 256, то есть его старший байт имеет значение, сформированное системным вызовом exit(1) – завершением процесса-потомка.

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

Ниже приведен текст, выведенный на экран в результате запуска программы:

 

Parent cuntinuation

Two created processes: 7466 and 7467

Start of Child: 1

Parent received end of 7466 with 1: 256 status

Start of Child: 2

Parent received end of 7467 with 1: 256 status

Parent process is finished

 

На основании последовательности выведенных сообщений можно догадаться, что операционная система, породив два процесса с идентификаторами 7466 и 7467, продолжила выполнение родительского процесса. Затем отработал процесс-потомок, созданный при нулевом значении n. И только потом отработал второй потомок.

 

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

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: