Linux 中的 fork、exec、wait 和 exit 系统调用解释
可以单次、多次或同时执行的指令和数据序列称为程序。而过程就是这样的程序的执行。所以这些进程可以运行很多程序。在同一个进程中,操作系统可以加载不同的程序。重用的进程状态(例如当前目录、权限、文件句柄等)由新程序继承。这些事情与 fork()、exec()、wait() 和 exit() 等系统调用在同一级别完成。
在本文中,我们将通过示例和用例详细讨论 Linux 系统调用 fork()、exec()、wait() 和 exit()。
叉()
fork() 是 Linux/Unix 系统中非常特殊且有用的系统调用之一。进程使用它来创建作为自身副本的进程。在此类系统调用的帮助下,父进程可以创建子进程。直到子进程执行完毕,父进程才会被挂起。
fork() 的一些要点如下。
- 父进程将获取非零值的子进程ID。
- 零值返回给孩子。
- 如果在创建子进程时出现任何系统或硬件错误,则 -1 将返回给 fork()。
- 子进程获得的唯一进程ID,与任何现有进程组的ID都不匹配。
为了详细说明 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
等待()
与 fork 的情况一样,子进程被创建并执行,但父进程被挂起,直到子进程执行。在这种情况下,由于父进程的挂起,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()相当于exit()。
概要
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
你可以在上面的fork()、wait()的例子中看到exit()函数的使用。使用 exit() 系统调用来终止进程。
结论
在本文中,我们通过一些示例详细学习了 fork()、exec()、wait() 和 exit() 系统调用。有关更多详细信息,请尝试使用这些系统调用运行程序并查看结果。谢谢你!