Объяснение системных вызовов fork, exec, wait и exit в Linux
Последовательность инструкций и данных, которые могут выполняться один раз, несколько раз или одновременно, называются программами. И процесс представляет собой выполнение таких программ. Таким образом, эти процессы могут запускать множество программ. В одном и том же процессе операционная система может загружать разные программы. Повторно используемые состояния процессов, такие как текущие каталоги, привилегии, дескрипторы файлов и т. д., наследуются новыми программами. Такие вещи выполняются на том же уровне, что и системные вызовы, такие как fork(), exec(), wait() и exit().
В этой статье мы собираемся подробно обсудить системные вызовы Linux fork(), exec(), wait() и exit() с примерами и вариантами использования.
вилка()
fork() — это один из системных вызовов, который очень специфичен и полезен в системах Linux/Unix. Он используется процессами для создания процессов, которые являются копиями самих себя. С помощью таких системных вызовов дочерний процесс может быть создан родительским процессом. Пока дочерний процесс не будет выполнен полностью, родительский процесс приостанавливается.
Некоторые из важных моментов в fork() заключаются в следующем.
- Родительский процесс получит идентификатор дочернего процесса с ненулевым значением.
- Нулевое значение возвращается дочернему элементу.
- Если при создании дочернего элемента возникнут какие-либо системные или аппаратные ошибки, в fork() возвращается -1.
- Поскольку уникальный идентификатор процесса, полученный дочерним процессом, не соответствует идентификатору какой-либо существующей группы процессов.
Чтобы подробнее рассказать о fork(), давайте рассмотрим пример, поясняющий концепцию fork().
sudo vim fork.c
Вот код для его копирования/вставки:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid==0)
{
printf("It is the child process and pid is %d\n",getpid());
exit(0);
}
else if(pid > 0)
{
printf("It is the parent process and pid is %d\n",getpid());
}
else
{
printf("Error while forking\n");
exit(EXIT_FAILURE);
}
return 0;
}
Выход:
$make fork
Запустив скрипт, мы получим результат, как показано на скриншоте ниже.
./fork
исполнитель()
Exec() — это такой системный вызов, который выполняется путем замены текущего образа процесса новым образом процесса. Однако исходный процесс остается новым процессом, но новый процесс заменяет головные данные, данные стека и т. д. Он запускает программу из точки входа, загружая программу в текущее пространство процесса.
Чтобы уточнить больше, давайте возьмем пример, показанный ниже.
sudo vim exec.c
И вот код:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
main(void) {
pid_t pid = 0;
int status;
pid = fork();
if (pid == 0) {
printf("I am the child.");
execl("/bin/ls", "ls", "-l", "/home/ubuntu/", (char *) 0);
perror("In exec(): ");
}
if (pid > 0) {
printf("I am the parent, and the child is %d.\n", pid);
pid = wait(&status);
printf("End of process %d: ", pid);
if (WIFEXITED(status)) {
printf("The process ended with exit(%d).\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("The process ended with kill -%d.\n", WTERMSIG(status));
}
}
if (pid < 0) {
perror("In fork():");
}
exit(0);
}
Выход:
make exec
Запустив скрипт, мы получим результат, как показано на скриншоте ниже.
./exec
ждать()
Как и в случае с ветвлением, дочерние процессы создаются и выполняются, но родительский процесс приостанавливается до тех пор, пока не выполнится дочерний процесс. В этом случае системный вызов wait() активируется автоматически из-за приостановки родительского процесса. После того, как дочерний процесс завершает выполнение, родительский процесс снова получает управление.
Чтобы подробнее рассказать о wait(), давайте рассмотрим пример, поясняющий системный вызов wait().
sudo vim wait.c
Вот пример кода:
#include<stdio.h> // printf()
#include<stdlib.h> // exit()
#include<sys/types.h> // pid_t
#include<sys/wait.h> // wait()
#include<unistd.h> // fork
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid==0)
{
printf("It is the child process and pid is %d\n",getpid());
int i=0;
for(i=0;i<8;i++)
{
printf("%d\n",i);
}
exit(0);
}
else if(pid > 0)
{
printf("It is the parent process and pid is %d\n",getpid());
int status;
wait(&status);
printf("Child is reaped\n");
}
else
{
printf("Error in forking..\n");
exit(EXIT_FAILURE);
}
return 0;
}
Выход:
make wait
Запустив скрипт, мы получим результат, как показано на скриншоте ниже.
./wait
Выход()
Exit() — это такая функция или один из системных вызовов, который используется для завершения процесса. Этот системный вызов определяет, что выполнение потока завершено, особенно в случае многопоточной среды. Для дальнейшего использования фиксируется состояние процесса.
После использования системного вызова exit() все ресурсы, используемые в процессе, извлекаются операционной системой, а затем завершают процесс. Системный вызов Exit() эквивалентен выходу().
Краткое описание
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
Вы можете увидеть использование функции exit() в приведенных выше примерах fork(), wait(). Использование системного вызова exit() предназначено для завершения процесса.
Заключение
В этой статье мы подробно изучили системные вызовы fork(), exec(), wait() и exit() с некоторыми примерами. Для получения более подробной информации попробуйте запустить программы с помощью этих системных вызовов и посмотрите результат. Спасибо!