Linux进程复制与替换(๑•̀ㅂ•́)و✧

⛄️ printf函数输出问题

printf函数不会直接将数据输出到屏幕,而是首先放到缓冲区,只有以下四种情况之一满足的时候,才会刷新缓冲区:

  1. 缓冲区满了,会自动刷新缓冲区
  2. 强制刷新缓冲区的时候 fflush
  3. 程序结束的时候,如果缓冲区还有数据的话,会执行刷新指令
  4. 当printf函数中含有换行符的时候,会强制刷新缓冲区,输出其中的数据

比如下面这段程序
test.c
在这里插入图片描述
对其进行编译执行的时候,现象是,先睡眠3秒,再输出printf里面的数据,为什么这样呢?
其原因是printf中的hello会先放入缓冲区中,当满足上面提到的四种情况才会将其中的数据输出,否则不会输出,程序先睡眠3秒,执行到退出命令时,检查缓冲区,这个时候发现有数据,就将数据刷新出来,所以hello显示在屏幕上。
如下图所示:
在这里插入图片描述
但是如果这个时候在printf函数后面加上一个fflush强制刷新,或者在其后面加上一个换行符号,那么会先输出hello,后睡眠3秒,如下图所示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
其中的stdout为屏幕标准输入流,执行之后效果如下:
在这里插入图片描述

如果退出函数为_exit(0),则不会刷新缓冲区,如下图所示:
直接连hello就不输出了,十分神奇,其原因就是因为没有刷新缓冲区导致的
在这里插入图片描述

🐑 主函数参数介绍

int main(int argc, char* argv[], char* envp[])
//argc 参数个数
//argv 参数内容
//envp 环境变量

可以写一段代码,来显示这些参数都是什么值:
在这里插入图片描述

🍄 复制进程fork

🍇 fork方法

pid_t fork(void);

函数的返回类型pid_t实质是int类型,Linux内核2.4.0版本对于pid_t的定义为:

typedef int  __kernel_pid_t;
typedef __kernel_pid_t pid_t;

一旦调用fork就会新生成一个进程,其中调用fork函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的pid,在子进程中返回0,失败返回-1。
开辟子进程示意图,和返回的pid示例,可以参考下图:
在这里插入图片描述
对于fork之后,子进程和父进程的判断,我们可以采用对其返回的pid进行判断来进行区分,如果是0那么就是子进程,如果非0那么就是父进程。
fork之后,父子进程并发运行。
看一下fork的声明:
在这里插入图片描述

🌴 示例

写一端代码,来实现演示一下fork函数的作用,如下图所示:
示例1:
下面是一段代码,一个父进程,生成了一个子进程,父子进程做不同的事情:
在这里插入图片描述

在这里插入图片描述
父进程的父进程ppid为2618,父进程的pid为5834,子进程的当前进程为5835,子进程的父进程ppid为5834,整个程序的过程如下图:
在这里插入图片描述
示例2:
这里面写了一个C语言程序,C语言里面有一个循环,循环里面一个fork函数,完了输出一个A
在这里插入图片描述
运行该程序,结果如下图所示:
输出了6个A
在这里插入图片描述
为什么会出现6个A,其原理和过程如下图所示:
在这里插入图片描述

🍋 写时拷贝

fork函数为进程开辟一个子进程的时候,将父进程的空间页表赋值一份给子进程,但是如果没有对某个页表的数据进行修改,那么父子进程会共享这些空间,而如果要改变某个页表中的数据,即写入某个页表,那么子进程会再次分配一个相同的页表,这个页表大小与要改变数据的页表大小一样,则子进程会使用这个新的页表区,对数据进行改变,如下图所示:
在这里插入图片描述

🍬 物理地址和逻辑地址

C语言程序,在未编译的时候,已经给其中某些变量和函数入口地址设置了逻辑地址,而在编译之后,这些地址不变,而一些变量的地址会在某个范围之内随机分配,这种是为了程序安全所设计的,原理如下图所示
在这里插入图片描述

🐘 僵死进程

🌿 定义

看一下僵死进程的原理,子进程先于父进程结束,父进程没有调用wait()函数获取子进程的退出码,如下图所示:
在这里插入图片描述
但是在系统中,虽然父进程没有获取子进程的退出码,在子进程结束而父进程未结束的时候,子进程是僵死状态,但是当父进程结束的时候,系统在回收父进程的同时也会回收子进程:
在这里插入图片描述
为了观察上面这个效果,我们来看下面这段代码
在这里插入图片描述
那么对于这段代码编译运行之后,调用ps命令检查当前进程时,可以观察到下面的现象:
在这里插入图片描述

🍤 孤儿进程

孤儿进程指的是,父进程先于子进程结束,导致子进程没有了父进程,使得子进程成了孤儿进程,如下图所示:
在这里插入图片描述
但是父进程死去,子进程并不是不能继续运行下去了,Linux系统给这种孤儿进程分配一个统一的父进程:Init进程,其pid为1,所以在其接管孤儿进程之后,孤儿进程的父进程pid为1,其原理如下图所示:
在这里插入图片描述
但是由于从某一版本的Linux更新之后,具体我也不知道哪一版本开始,系统开始对于孤儿进程的接管跑到层级结构的上一层接管,并不是固定的由init进程接管,init进程是终极父进程,是所有进程的最终极的父进程。
为了看到这一情况,我们可以通过下面这段代码来进行观察:
在这里插入图片描述
运行代码,我们可以看到下面的情况:
在这里插入图片描述
从这里面我们可以看出是pid为1638的一个进程接管了此孤儿进程,那么这个进程是什么进程呢,我们可以查看一下所有的进程,查看一下pid为1638的为什么进程,采用下面这条命令:

ps -aux

如下图:
在这里插入图片描述
可以看出接管这个孤儿进程的为当前用户的最顶层进程,可以验证上面这个进程。

🍯 wait()函数

为了解决僵死进程的情况,可以使用wait函数,来对子进程进行等待,直到子进程结束,并且父进程获取子进程的退出码为止,使用方法如下图所示:
需要导入sys/wait库
在这里插入图片描述
获取是否成功退出、退出码的函数:
在这里插入图片描述
那么通过下面这段代码进行使用:
在这里插入图片描述

运行这段代码得到:
在这里插入图片描述
由此我们可以看出,父进程在没获得子进程的退出码之前一直在wait,即阻塞状态,直到获得子进程的退出码之后开始执行,注意这里面的退出码与exit(int exit_id)中的退出状态码有关,如果这里为3,那么上面的val就为3

🍭 文件操作的系统调用

示例1:
在这里插入图片描述
在这里插入图片描述
示例2:
将etc/passwd复制到当前文件夹,将其显示出来:
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值