Linux | 进程概念详解:冯诺依曼体系结构、进程基本概念、PCB、进程组织、fork()创建子进程、进程运行逻辑

文章目录

  • 进程概念
    • 1、冯诺依曼体系结构
    • 2、进程
      • 2.1基本概念
      • 2.2描述进程-PCB
      • 2.3组织进程
      • 2.4查看进程
      • 2.5通过系统调用获取进程标识符
      • 2.6通过系统调用创建进程-fork初识
        • ==头文件与返回值==
        • fork函数的调用逻辑和底层逻辑

进程概念

1、冯诺依曼体系结构

Linux | 进程概念详解:冯诺依曼体系结构、进程基本概念、PCB、进程组织、fork()创建子进程、进程运行逻辑_第1张图片

目前我们认识的计算机中,都是由一个个硬件构成

  • 输入单元:键盘、鼠标、写字板等
  • 中央处理器(CPU):含有运算器和控制器等
  • 输出单元:显示器,打印机等

对于冯诺依曼一些结构,有以下几点注意:

  • 存储器指的是内存
  • 不考虑缓存情况,这里的CPU能且只能对内存进行读写, 不能访问外设
  • 外设(输入设备或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取
  • 总结就是:所有设备只能直接和内存打交道

总的来说,对冯诺依曼体系结构的理解,不能停留在概念上,要深入到对软件数据流的理解上,例如,解释从登陆上qq开始和某个好友聊天这个过程中数据的流动过程:

2、进程

2.1基本概念

程序的一个执行实例,正在执行的程序等。担当分配系统资源(CPU时间,内存)的实体。

2.2描述进程-PCB

进程信息被放在进程控制块(一个数据结构),叫做PCB,Linux操作系统下的PCB是task_struct
进程 = 内核数据结构(PCB) + 代码和数据

task_struct内容分类

  • **标识符:**描述本进程的唯一标识符,用来区别其他进程
  • **状态:**任务状态,推出代码,推出信号
  • **优先级:**相对于其他进程的优先级
  • **程序技术器:**程序中即将被执行的下一条指令的地址
  • **内存指针:**包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • **上下文数据:**进程执行时处理器的寄存器中的数据
  • **io状态信息:**包括显示器的io请求,分配给进程的io设备和被进程使用的文件列表
  • **记账信息:**可能包括处理器时间总和,使用的时钟数总和,时间限制,记帐号等

2.3组织进程

可以在内核源代码里找到,所有运行系统里的进程都以task_struct链表的形式存在内核里

2.4查看进程

如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹。

大多数进程信息同样可以使用top和ps这些用户级工具来获取

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.5通过系统调用获取进程标识符

  • 进程id(PID)
  • 父进程id(PPID)
#include 
#include 
#include 
int main()
{
 	printf("pid: %d\n", getpid());
 	printf("ppid: %d\n", getppid());
 	return 0;
}

2.6通过系统调用创建进程-fork初识

  • 使用man手册运行man fork认识fork函数
  • fork有两个返回值
  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
头文件与返回值
  • 头文件:unistd.h

  • 函数原型:pid_t fork(void);

  • 父进程中,fork返回新创建子进程的进程ID

  • 子进程中,fork返回0

fork函数的调用逻辑和底层逻辑

在上文介绍PCB的时候有提到过,进程由内核数据结构和代码、数据两部分组成。因此每个进程都会有自己的PCB即task_struct结构体。当调用了fork函数后,系统创建子进程,即创建一个属于子进程的task_struct,将父进程的大部分属性拷贝过去(不在内的如pid、ppid),由于父子进程属于同一个程序,他们的代码是共用的,但是两个进程同时访问一个变量的时候会出现冲突问题,因此子进程会将它将要访问的数据做一份额外的拷贝,也就是子进程访问拷贝出来的数据,然后父子进程就有了属于各自的数据,对变量的操作也是独立的。

fork函数创建子进程过程

  • 创建子进程PCB
  • 填充PCB对应的内容属性
  • 让子进程和赴京城指向同样的代码
  • 父子进程都是有独立的task_struct,已经可以被CPU调度运行了

问:为什么fork函数调用完后会返回两个值,这和寻常的函数不是不一样么?

在fork函数中,创建子进程的步骤完成后,在return返回之前,父子进程已经可以被CPU调度运行了,也就是说,在return前fork函数执行了父子两个进程,return是作为父子进程的共有程序,他们都会各自返回一个值,因此整体看fork函数会返回两个值,分别属于调用fork函数中父子进程的返回值。

#include 
#include 
#include 
int main()
{
	int ret = fork();
 	printf("hello proc : %d!, ret: %d\n", getpid(), ret);
 	sleep(1);
 	return 0;
}
  • 由于父子进程的代码是一样的,因此如果需要使得父子进程执行不一样的代码,可以使用if加上返回值的条件限定来进行父子进程分流

    #include 
    #include 
    #include 
    int main()
    {
     	int ret = fork();
    	 if(ret < 0){
     		perror("fork");
    		return 1;
     }
     else if(ret == 0){ //child
     	printf("I am child : %d!, ret: %d\n", getpid(), ret);
     }else{ //father
     	printf("I am father : %d!, ret: %d\n", getpid(), ret);
     }
     return 0;
    }
    

你可能感兴趣的:(Linux,linux,进程)