【Linux】进程与可执行程序的关系&&fork创建子进程&&写实拷贝的理解

简介: 【Linux】进程与可执行程序的关系&&fork创建子进程&&写实拷贝的理解

一、进程与可执行程序之间关系的理解

       系统会将此时在系统运行的进程的各种属性都以文件的形式给你保存在系统的proc目录下。运行一个程序的时候,本质就是把磁盘中的程序拷贝到内存中,当一个进程运行起来的时候,它本质已经和磁盘中的可执行程序没有直接关系了。

当前我的myprocess程序正在运行

而此时我将其对应的可执行程序删掉

这个进程所对应的可执行程序已经被语法高亮了,证明已经被删掉了

        而此时我的可执行程序仍在运行,这也从侧面证明了当一个进程运行起来的时候,它本质已经和磁盘中的可执行程序没有直接关系了。从上面的截图中我们也可以看到,/proc目录下的虚拟文件系统是会记录下进程的工作目录和对应可执行程序的路径,/proc目录下记录的进程信息与PCB中的某些信息有重叠,比如说PCB中同样也会记录下进程的工作目录和对应可执行程序的路径。

二、通过系统调用创建进程

fork:创建子进程

       fork之后有两个执行分支,fork之后代码共享,也就是说fork之后的代码父进程和子进程都会执行。下面的5986进程就是bash进程。

#include <stdio.h>
  2 #include <unistd.h>
  3 int main()
  4 {
  5     printf("before fork : pid:%d ppid:%d\n", getpid(), getppid());
  6 
  7     pid_t id = fork();
  8 
  9     printf("after fork : pid:%d ppid:%d returnid: %d\n", getpid(), getppid(), id);
 10 
 11                                                                                                                            
        return 0;
     }

       第二条printf语句在fork之后,为父子进程共享,所以第二条printf语句会打印两次。我们也可以看到,其中父子进程fork的返回值是不一样的,父进程fork返回的是子进程的pid,子进程返回的是0。

       那这里就会有疑问了,为什么fork给父进程返回子进程的pid,给子进程返回0?原因是在进程中,一个父进程可能会有多个子进程,父进程想要管理子进程必须通过子进程的标识符,所以父进程必须知道子进程的标识符,而子进程只需要关心自己是否成功创建了,所以返回0。

       那fork函数为什么会返回两次呢?原因是fork本身是一个系统调用函数,fork内部本身也会有很多代码的,当fork函数执行到最后return pid的时候,它的核心工作已经做完了,子进程其实已经被创建出来了,return pid也是一条语句,既然父子进程已经都被创建出来了,那么父子进程当然都可以执行return pid语句咯,所以return pid被执行了两次,所以fork就会返回两次。

       那上面的id可是同一个变量啊,怎么会即大于零,又等于零呢?这和linux中的虚拟地址有关,也就是说,一个变量可以指向不同的地址空间。

写实拷贝

       任意进程之间是具有独立性的,不会互相影响创建一个进程的时候,系统中就会多一个进程,当子进程创建时,系统就必须为子进程创建出一个全新的PCB(task_struct),父进程会把自己PCB中很多内容拷贝给子进程的PCB,也就是说,子进程被创建,是以父进程为模版的进程都有自己的代码和数据,系统创建出来的子进程的PCB默认就会指向父进程的代码和数据,想让父子进程分别执行不同的程序,那就可以在代码中根据父子进程fork返回值的不同设置ifelse语句,让父子进程分别执行不同的代码。上面说到父子进程共享代码和数据,当父子进程任意一方要对数据进行修改时,都可能会对另一方造成影响,上面又说到任意进程之间是具有独立性的,不会互相影响,那么这时操作系统就会介入,将要修改的数据给子进程(以子进程修改数据为例)拷贝一份,让子进程修改拷贝的这一份数据,子进程也不再指向原来的那一份数据,而是指向修改拷贝的这一份数据。这就叫做写实拷贝

相关文章
|
2月前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
187 6
|
3月前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
675 2
|
3月前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
70 2
|
1月前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
40 1
|
1月前
|
消息中间件 存储 Linux
Linux手账—exec和fork
本文介绍了Linux系统中进程控制的核心功能——`fork`和`exec`系列函数。`fork`用于创建新进程(子进程),继承父进程的资源但拥有独立的地址空间;`exec`系列函数则在当前进程中执行新程序,替换原有地址空间。文章详细解析了这些函数的基本概念、用法及工作原理,强调了它们在多进程编程中的重要性。
34 0
|
2月前
|
消息中间件 分布式计算 Java
Linux环境下 java程序提交spark任务到Yarn报错
Linux环境下 java程序提交spark任务到Yarn报错
45 5
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
102 3
|
2月前
|
Linux
linux内核执行fork时对写时复制的设置
linux内核执行fork时对写时复制的设置
|
3月前
|
Linux Windows Python
最新 Windows\Linux 后台运行程序注解
本文介绍了在Windows和Linux系统后台运行程序的方法,包括Linux系统中使用nohup命令和ps命令查看进程,以及Windows系统中通过编写bat文件和使用PowerShell启动隐藏窗口的程序,确保即使退出命令行界面程序也继续在后台运行。
|
3月前
|
存储 Linux 调度
Linux 0.11 fork 函数(二)
Linux 0.11 fork 函数(二)
42 0
下一篇
无影云桌面