当前位置: > 系统教程 > 本文fork调用失败的原因及解决办法(二):进程等待

本文fork调用失败的原因及解决办法(二):进程等待

发布时间:2021-10-06 11:02:33 文章来源:Linux系统下载站 浏览量:

[导读] : 在linux中fork函数它从已存在进程中创建一个新进程。进程调用fork,当控制转移到内核中的fork代码后,内核会进行:否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。

本文fork调用失败的原因及解决办法(二):进程等待

本文基于CentOS,深入讲解进程创建、进程等待、进程程序替换、进程终止、shell运行原理,以及一个简单的shell。

内容

一、进程创建1. fork 函数

Linux 中的 fork 函数从现有进程创建一个新进程。新进程是子进程,原进程是父进程。

#include 
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1

进程调用fork。当控制权转移到内核中的 fork 代码时,内核将继续:

(1)给子进程分配新的内存块和内核数据结构;

(2) 将父进程的部分数据结构内容复制到子进程;

(3)将子进程添加到系统进程列表中;

(4)fork 返回并启动调度器调度。

当一个进程调用fork时,有两个进程具有相同的二进制代码。他们都跑到同一个地方。父进程在fork之前独立执行,在fork之后,父子两个执行流分别执行。fork后,由调度器先执行

决定。

2. fork 函数返回值

子进程返回0,

父进程返回子进程的pid。

3. 写时复制

代码在父子之间共享。父子不写的时候,数据也是共享的。当任何一方尝试写入时,通过写入时复制完成每一方的副本。详情见下图:

内核只为新生成的子进程创建一个虚拟空间结构。它们是从父进程的虚拟最终结构拷贝过来的,但是没有为这些段分配物理内存,也没有分配段。它们共享父进程的物理空间。当发生改变相应段的行为时,为子进程的相应段分配物理空间。

4. fork 用法

父进程想要​​复制自己,以便父子进程同时执行不同的代码段。

该进程需要执行不同的程序。

5. fork 调用失败的原因

分叉调用失败的主要原因包括:

系统进程过多

实际用户的进程数超过限制

二、进程终止

当进程执行完最后一条语句并通过系统调用exit()请求操作系统删除自身时,进程终止。这时,进程可以将状态值(通常是一个整数)返回给父进程(通过系统调用wait())。操作系统会释放所有进程资源,例如物理和虚拟内存、打开的文件和 I/O 缓冲区。

进程退出场景:

代码运行完毕,结果正确

代码运行完毕,但结果不正确

代码异常终止

1.进程的常用退出方法

正常终止(可以通过 echo $? 查看进程退出代码):

从主返回

呼叫退出

_出口

异常退出:

ctrl + c,信号终止

2._exit 函数

它可以在程序的任何地方使用。

void _exit(int status);
参数:status 定义了进程的终止状态,父进程通过wait来获取该值

虽然状态是int,但父进程只能使用低8位。所以当_exit(-1),在终端执行$?时,发现返回值为255。

3.退出函数

#include 
void exit(int status);

Exit在最后也会调用exitlinux查看进程,但是在调用exit之前,它还会执行:

linux查看僵死进程_linux查看进程_linux查看进程内存占用

(1)通过atexit或on_exit执行用户定义的清理函数;

(2)关闭所有打开的流,缓存的数据全部写入;

(3) 调用 _exit。

4.返回退出

Return 是一种更常见的退出进程的方式。执行return n相当于执行exit(n),因为调用main的runtime函数会把main的返回值作为exit的参数。

三、进程等待

如果子进程退出,如果父进程忽略它,可能会导致“僵尸进程”问题,进而导致内存泄漏。一旦进程变成僵尸状态,kill -9 就无能为力了。最后,我们需要知道父进程分配给子进程的任务是如何完成的。例如,如果子进程完成,结果是否正确,或者是否正常退出。父进程回收子进程的资源,通过等待的过程获取子进程的退出信息。

1. 等待方法

#include
#include
pid_t wait(int*status);