一.fork函数
在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程
头文件:
#include <unistd.h>
我们来通过man手册来查看下内容:
除了头文件,我们还可以看看返回值,什么是pid呢?
其就是一个进程的标识,所以fork返回的是一个pid
但是用了fork之后,会出现两个进程奥,所以父子进程分别返回什么呢?
实际上,父进程返回的是子进程pid,而子进程返回的是0,当然出错时返回-1
步骤:
进程调用fork,当控制转移到内核中的fork代码后,内核做:
分配新的内存块和内核数据结构给子进程
将父进程部分数据结构内容拷贝至子进程
添加子进程到系统进程列表当中
fork返回,开始调度器调度
fork调用失败的原因:
1.系统中有太多的进程
2.实际用户的进程数超过了限制
补充:二进制文件中变量会变成虚拟空间地址
验证:
结果:
虽然是if和else,但是都是可以执行的,因为会出现两个pid对应父子进程
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定
二.写时拷贝
我们知道当fork之后,子进程和父进程是指向同一块内存空间的,所以为什么不直接拷贝一份父进程代码给子进程呢?
原因和之前相似,我们申请空间的时候是不是也是不直接开辟空间,这与操作系统有关,便于操作系统资源利用最大化,所以当我们需要对于父子进程分别写入内容的时候,才会拷贝,此时的拷贝称为:“写时拷贝”
如何实现的呢?其实还是通过页表来实现的,相同操作“缺页中断”
页表扩展:
目前对于页表我们知道页表对于虚拟空间和内存可以形成一种对应的映射关系,但是页表是否还有其他作用呢?是的实际上页表还可以满足其他需求
例如:页表是存在权限的
#include <bits/stdc++.h>
using namespace std;
int main()
{
char* str="hello Linux";
str[0]='1';
cout<<str<<endl;
return 0;
}
如果你去测试这段代码,是可以运行的,但是结果为空,为什么呢?
你认为是const修饰吗?
如果是因为没写const,它肯定会直接报错的,编译都不可能过,所以该代码能够运行成功,肯定不是cosnt问题,那么只可能是其他问题了,下面我告诉大家问题原因:
页表是有权限的,对于上速代码实际上只有读权限,所以是不能够对内存进行修改的,所以error
三.进程终止
进程退出场景;
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
我们知道当我们写的一个程序中:如果是非main函数调用完毕后,仅仅表示为该函数调用完毕,而非进程结束,只有当我们写的main函数return才表明进程结束,并且我们可以通过返回值来确定该进程执行情况
对于main函数的返回值:0表示为成功,非0表示失败
非0表示失败原因:
因为我们的失败原因可以有非常多种,所以用不同数字来表示不同的失败原因
对于一个正常终止的进程,我们可以通过以下指令查看:
echo $?;
//表示进程退出值查询
下面我们来认识两个新函数:
exit/_exit:
#include <unistd.h>
void _exit(int status);
参数:status 定义了进程的终止状态,父进程通过wait来获取该值
#include <unistd.h>
void exit(int status);
相同点:头文件相同,两个都可以结束进程,无论是否在main函数中
不同点:exit结束进程时会刷新,而_exit不会刷洗进程
如果我们的进程是出现异常退出,通常情况是因为收到了错误信号,如果我们的进程一直退不出来也可以通过kill相关指令杀死进程
我们可以利用kill相关的信号杀死进程,常用的如9号
补充:
return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做 exit的参数
最后,感谢大家的支持!!!