Системный вызов fork()
Добавлено: 10 авг 2016, 16:51
Для линуксоидов Си это не только язык программирования, это еще
удобный уровень абстракции понимания работы компьютера в целом.
Значит даже поверхностные знания этого языка, пусть не позволяющие успешно программирвать,
формируют связанную, правильную картину работы сисетемы и взаимодействия процессов в ней.
Это главная причина уделять внимание программированию на Си
даже если изначально не ставилась задача по овладению им в совершенстве
и время потраченное на его освоение будет в любом случае не напрасным.
На мой взгляд один из самых интересных моментов работы программы это
клонирование процессов и общение между форками через каналы.
В данном случае мы рассматриваем полудуплексный канал пайп. Родственник
вертикальной черточки в баше.
Полудуплексный канал создается в пространстве ядра. Там он имеет определенную
сущьность но пользователю на руки выдаются только дискрипторы от него.
Но сначала по порядку. Скомпилированная программа начинает свой бег.
пока на ее пути не встречается системный вызов fork(). Этот
системыный вызов порождает почти полную копию существующего процесса - программы.
Как же различить в программе кто из них кто и как разделить последующий код
между двумя ветками? Системный вызов fork() возвращает разные значения.
В процесс родитель он возвращает номер дочернего процесса, а в дочернем
процессе возвращает ноль. И если мы в коде предусмотрим переменную например
с именем pid и присвоим ей возваращаемое значение от вызова fork()
то мы легко сможем различить два процесса - две паралельные программы
по ее содержанию.
Поместив в коде переключатель switch или как у меня условный переход
мы можем лекго обазначить какому процессу предназначен тот или иной
участок кода. В родительком процессе переменная получает какое то
число - номер клонированного процесса, во всяком случае больше нуля,
и занчит мы можем отделить его по условию if(pid > 0).
Другое условие определяет другой участок кода для дочернего процесса
по условию if(pid == 0). Теперь нам не составит труда написать нужный
код в программе отдельно для каждого процесса и более того обменятся через
пайп информацией. Системный вызов fork() клонирует так же и переменные
содержащие дискрипторы созданных каналов, занчит
нам надо предусмотреть и создать канал до клонирования программы. У меня
в программе дочерний процесс посылает данные родительскому процессу, поэтому
в дочернем я закрываю выходной дискриптор а в родительском соответственно
закрою входной. Иначе такой канал не сможет определить конец передачи.
Чаще всего такой паре процессов дают устоявшееся название, сервер -
то которое читает из пайпа и клиент - то которое отсылает данные в канал.
[album]438[/album]
[album]439[/album]
удобный уровень абстракции понимания работы компьютера в целом.
Значит даже поверхностные знания этого языка, пусть не позволяющие успешно программирвать,
формируют связанную, правильную картину работы сисетемы и взаимодействия процессов в ней.
Это главная причина уделять внимание программированию на Си
даже если изначально не ставилась задача по овладению им в совершенстве
и время потраченное на его освоение будет в любом случае не напрасным.
На мой взгляд один из самых интересных моментов работы программы это
клонирование процессов и общение между форками через каналы.
В данном случае мы рассматриваем полудуплексный канал пайп. Родственник
вертикальной черточки в баше.
Полудуплексный канал создается в пространстве ядра. Там он имеет определенную
сущьность но пользователю на руки выдаются только дискрипторы от него.
Но сначала по порядку. Скомпилированная программа начинает свой бег.
пока на ее пути не встречается системный вызов fork(). Этот
системыный вызов порождает почти полную копию существующего процесса - программы.
Как же различить в программе кто из них кто и как разделить последующий код
между двумя ветками? Системный вызов fork() возвращает разные значения.
В процесс родитель он возвращает номер дочернего процесса, а в дочернем
процессе возвращает ноль. И если мы в коде предусмотрим переменную например
с именем pid и присвоим ей возваращаемое значение от вызова fork()
то мы легко сможем различить два процесса - две паралельные программы
по ее содержанию.
Поместив в коде переключатель switch или как у меня условный переход
мы можем лекго обазначить какому процессу предназначен тот или иной
участок кода. В родительком процессе переменная получает какое то
число - номер клонированного процесса, во всяком случае больше нуля,
и занчит мы можем отделить его по условию if(pid > 0).
Другое условие определяет другой участок кода для дочернего процесса
по условию if(pid == 0). Теперь нам не составит труда написать нужный
код в программе отдельно для каждого процесса и более того обменятся через
пайп информацией. Системный вызов fork() клонирует так же и переменные
содержащие дискрипторы созданных каналов, занчит
нам надо предусмотреть и создать канал до клонирования программы. У меня
в программе дочерний процесс посылает данные родительскому процессу, поэтому
в дочернем я закрываю выходной дискриптор а в родительском соответственно
закрою входной. Иначе такой канал не сможет определить конец передачи.
Чаще всего такой паре процессов дают устоявшееся название, сервер -
то которое читает из пайпа и клиент - то которое отсылает данные в канал.
Код: Выделить всё
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int fd[2]; //массив входного и выходного дискрипторов канала
char buff[] = "Hello World!";
char xbuff[strlen(buff)];
int ret;
size_t size;
pid_t pid;
if(pipe(fd) < 0) //создаем канал и определяем дискрипторы в массиве fd
perror("pipe!"), exit(EXIT_FAILURE);
if((pid = fork()) == -1) //с момента вызова fork() мы получим две одинаковых программы.
{ //но в переменные pid уже будут возвращены разные значения.
perror("fork!"), exit(EXIT_FAILURE);
}
else if(pid == 0)
{
printf("%s текущий процесс: %d родительский: %d\n", "Child", getpid(), getppid());
close(fd[0]); //закрываем выходной дискриптор
size = write(fd[1], buff, strlen(buff));
printf("%s\n", "Выходим из дочернего процесса");
exit(size); //код возврата
}
else
{
printf("%s текущий процесс: %d дочерний: %d\n", "Parent", getpid(), pid);
close(fd[1]); //закрываем входной дискриптор.
read(fd[0], xbuff, 12); //считаем присланное сообщение в буфер
waitpid(pid, &ret, 0); //ожидаем код завершения д/п SIGCHILD
printf("%s %d\n", "Код возврата дочернего процесса:", WEXITSTATUS(ret));
printf("%s\n", xbuff);
}
return 0;
}[album]439[/album]