Linux——(三)进程概念

目录

  • 1. 冯诺依曼
  • 2. 操作系统
  • 3, 进程概念
  • 4. 进程状态
    • 4.1 概念
  • 4.2 linux下的进程状态分类:
  • 5 进程创建
    • 5.1 fork函数初识
    • 5.2 僵尸进程
    • 5.3 孤儿进程
  • 6. 环境变量
    • 6.1 常见环境变量
    • 6.2 和环境变量相关的命令
    • 6.3环境变量的接口
    • 6.3 例子,获取环境变量的 PATH 的值
    • 6.4 环境变量的特性具有进程之间的传递性的例子
  • 7. 程序地址空间
    • 7.1 虚拟地址空间

1. 冯诺依曼

计算机的硬件体系结构
五大硬件单元:输入设备(如:键盘),输出设备(如:显示器),运算器,控制器
Linux——(三)进程概念_第1张图片
所有的设备都是围绕内存工作的。CPU不能直接从输入设备取数据,而是要去存储器取数据(存储器最主要的工作就是数据缓冲)

  • 例子:QQ聊天发送消息

键盘输入信息(电信号转换为数字信号)键盘捕捉到我们的输入信息——>放内存缓冲起来——>交给CPU对信息进行处理(翻译输入了哪些字符)——>处理好了再次发给存储器——>通过输出设备网卡(通过网络进行发送信息,将我们的数字信号再次转换为电信号)——>到达对方电脑,对方的网卡接受我们的信号——交给CPU (处理信息)——>放入内存进行输出——>输出设备显示器

2. 操作系统

  • 概念

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。
笼统的理解,操作系统包括:
内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(例如函数库,shell程序等等)

  • 设计OS的目的

与硬件交互,管理所有的软硬件资源为用户程序(应用程序)提供一个良好的执行环境

  • 定位

在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
Linux——(三)进程概念_第2张图片

3, 进程概念

  • 进程基本概念
    用户的角度:是运行中的程序。
    操作系统的角度:是程序运行的动态描-PCB,其中包含程序运行的各项信息,实现操作系统对于运行中程序管理。(pcb描述信息:标识符-PID,内存指针,程序计数器,上下文数据进程状态,进程优先级,IO信息,记账信息)
    linux下:进程就是task_struct结构体。是操作系统对程序运行的描述,通过这些描述完成对进程的管理。
    课本概念:程序的一个执行实例,正在执行的程序等(程序:软件——就是程序员所写的代码,程序本质上都存储在硬盘,因为程序都存储在文件中,文件存储在硬盘里)。
    内核观点:担当分配系统资源(CPU时间,内存)的实体。

  • 描述进程-PCB
    进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
    课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct

4. 进程状态

4.1 概念

  1. 描述当前进程处于什么状态应该如何被操作系统调度管理。

  2. 进程状态种类:就绪、运行、阻塞。

4.2 linux下的进程状态分类:

  1. 运行态-R:正在运行的,以及拿到时间片就能运行的。
  2. 可中断休眠态-S:能够被打断的休眠状态。
  3. 不可中断休眠态-D:不可被打断的阻塞状态(最典型的就是磁盘休眠)
  4. 停止态-T:停止运行。
  5. 僵尸态-Z:程序退出后的中间等待处理状态。
    僵尸进程:僵尸态的进程,退出后资源没有完全被释放的进程 。
    产生:子进程先于父进程退出,为了保存自己的退出返回值,因此没有完全释放资源,等待父进程处理。
    避免:进程等待。
    处理:退出父进程。
    危害:资源泄露(内存+进程数量)。

5 进程创建

5.1 fork函数初识

输入命令:man fork
Linux——(三)进程概念_第3张图片
在这里插入图片描述

通过复制调用进程(谁调用他就复制谁)来创建一个子进程。子进程从fork之后进行运行。(这个复制是复制了大部分信息,不是复制全部信息比如进程ID就不会复制的。)
返回值:如果成功复制子进程则返回子进程PID,在父进程中返回子进程PID ;在子进程中返回0;失败返回-1。

  • 基本使用
  1. vi main.c :只打印一个“leihoua~~”信息
    vi main.c
#include   
  2 #include <stdlib.h>  
  3 #include <unistd.h>  
  4   
  5 int main()  
  6 {
  7         printf("leihoua~~\n");
  8         return 0;                                                                                                            
  9 } 

编译一下:
gcc main.c -o main
运行一下
./main
在这里插入图片描述

  1. 修改main.c :在打印信息之前进行fork();
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7   fork();                                                                                                                    
  8   printf("leihoua~~\n");                                  
  9   return 0;                                               
 10 }                                                         
~         

编译运行一下(步骤如一种)
Linux——(三)进程概念_第4张图片
父进程和子进程都打印了信息。fork()之后他们俩同时从fork之后运行程序。
3. 再次修改main.c:把print函数放到fork函数之前

 #include 
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 
  5 int main()
  6 {
  7 
  8   printf("leihoua~~\n");                                                                                                     
  9   fork();  
 10   return 0;
 11 }

编译运行:
在这里插入图片描述
我们发现只输出一次打印信息。因为子进程是fork之后才创建的,fork之后父进程和子进程都运行了return 0.
4. 为什么要创建子进程?
(1)分摊任务处理压力。(2)可以让子进程做另一件事情。这种最常用。
继续修改main.c 根据fork函数的返回值来区分父子进程
vi main.c

 #include   
  2 #include <stdlib.h>  
  3 #include <unistd.h>  
  4   
  5 int main()  
  6 {  
  7   
  8  pid_t pid =  fork();  
  9  if(pid >0)  
 10  {
 11   printf("i m parent\n");                                                                                                    
 12                              
 13  }else if(pid == 0)       
 14  {                        
 15     printf("i m child~\n");
 16                                    
 17  }    
 20   printf("hello !\n");                                                                                                                   
 23   return 0;                        
 24 }

编译运行一下
Linux——(三)进程概念_第5张图片

5.2 僵尸进程

产生原因:子进程先于父进程退出,为了保存退出原因,因此等待父进程获取状态释放资源。
危害:资源泄露(内存资源的泄露,进程数量的占有)
处理:退出父进程。

  1. vim main.c 代码
    1 #include<stdio.h>
    2 #include<unistd.h>
    3 #include<stdlib.h>
    4 
    5 int main()
    6 {
    7 
    8 
    9   pid_t pid = fork();
   10   if(pid > 0)
   11   {
   12 
   13     printf("i m parents~\n");
   14 
   15   }else if(pid == 0)
   16   {
   17     printf("i m a child\n");
   18     sleep(6);
   19     exit(0);  //退出进程;                                                                                                
   20   }
   21   while(1){
   22 
   23     printf(" i m a zoomProcess");
   24     sleep(1);
   25   }
   26   return 0;
   27 }

  1. vim makefile代码
3 main:main.c                                                                                                                
  4     gcc $^ -o $@

  1. 输入:make

Linux——(三)进程概念_第6张图片
从上图可以看出我们无法进行任何其他操作,必须中断这个僵尸进程,才能继续输入命令。所以我们必须结束这个僵尸进程。

  1. 如何关闭僵尸进程(kill是杀不死僵尸进程的,我们只能关闭僵尸进程的父进程)
    (1)查看僵尸进程的父id
    输入:ps -ef
    在这里插入图片描述
    (2)查看进程状态(比较详细信息)
    输入:ps -aux
    在这里插入图片描述
    (3)筛选一下我们的进程main
    输入:ps -aux | grep main
    Linux——(三)进程概念_第7张图片(4)由于我的shell无法通过ctrl +C进行进程终止,我都是使用Ctrl+Z结束了我的僵尸进程。可以看到上图很多Z状态进程的父进程(就是Z上面的T)都是T状态。为了杀死T状态的进程我这里使用了 kill -9 PPID
    Linux——(三)进程概念_第8张图片

5.3 孤儿进程

产生原因:父进程先于子进程退出,子进程就会成为孤儿进程。
特性:运行在后台,父进程变为1号进程(孤儿进程退出后不会成为僵尸进程)。
守护进程:特殊的孤儿进程,在孤儿进程的基础上脱离与终端之间的关系(比如新建回话)。

  1. vim main.c
    1 #include<stdio.h>                                                                                                        
    2 #include<unistd.h>
    3 #include<stdlib.h>
    4 
    5 int main()
    6 {
    7   
    8   
    9   pid_t pid = fork();
   10   if(pid > 0)
   11   {
   12 
   13     printf("i m parents~\n");
   14 
   15     sleep(6);
   16     exit(0);  //退出进程;
   17   }else if(pid == 0)
   18   {
   19     printf("i m a child\n");
   20   }
   21   while(1){
   22 
   23     printf(" i m a orphonProcess");
   24     sleep(1);
   25   }
   26   return 0;
   27 }

  1. makefile和不用变

  2. 继续make一下执行 ./mian
    Linux——(三)进程概念_第9张图片
    此时我们发现父进程退出了,但是我们仍然可以执行命令。此时子进程并没有,而是shell占据终端。但是它并没有退出,而是在后台继续运行。

  3. 查看孤儿进程的父进程 输入命名 ps -ef | grep main
    在这里插入图片描述
    孤儿进程的父进程就变成了1号进程。

6. 环境变量

保存程序运行环境的变量,特性:具有进程之间的传递性。

6.1 常见环境变量

  • PATH : 指定命令的搜索路径 (程序默认的运行路径)
    比如现在我们在shell中输入mian它就不能直接运行,因为shell运行文件是要在指定路径下运行,我们需要告诉shell,main文件在哪里,我们输入 ./main ,此时才可以运行。
    在这里插入图片描述
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash。

6.2 和环境变量相关的命令

  1. env: 显示所有环境变量

  2. echo: 显示某个环境变量值(打印某个指令变量的数据)
    Linux——(三)进程概念_第10张图片

  3. export: 设置一个新的环境变量(声明一个环境变量)
    Linux——(三)进程概念_第11张图片

  4. set: 显示本地定义的shell变量和环境变量
    Linux——(三)进程概念_第12张图片

  5. unset: 清除环境变量
    Linux——(三)进程概念_第13张图片

6.3环境变量的接口

  1. 通过系统调用获取环境变量:char *getenv(char *name),输入:man getenv
    Linux——(三)进程概念_第14张图片
    name :环境变量名称;
    返回值:对应name环境变量的数据,如果找不到返回NULL

6.3 例子,获取环境变量的 PATH 的值

  • vim env.c
  1 #include<stdio.h>
  2 #include <unistd.h>
  3 #include<stdlib.h>
  4 
  5 
  6 int main()
  7 {
  8   char *ptr = getenv("PATH");
  9   if(ptr == NULL)
 10   {
 11     printf("there is no PATH\n");
 12   }else {
 13     printf("%s\n",ptr);
 14   }
 15                                                                                               
 16   return 0;
 17 }

  • makefile
2 env:env.c                                                                                     
  3     gcc $^ -o $@

  • make

Linux——(三)进程概念_第15张图片

6.4 环境变量的特性具有进程之间的传递性的例子

  • vim env.v
  1 #include<stdio.h>
  2 #include <unistd.h>
  3 #include<stdlib.h>
  4 
  5 
  6 int main()
  7 {
  8   char *ptr = getenv("MYVAL");
  9   if(ptr == NULL)
 10   {
 11     printf("there is no MYVAL\n");                                                            
 12   }else {
 13     printf("%s\n",ptr);
 14   }
 15 
 16   return 0;
 17 }

  • makefile文件和上一个例子一样,不用变。make一下。体会环境变量相较于普通变量的传递性:

Linux——(三)进程概念_第16张图片

7. 程序地址空间

本质上就是操作系统为进程通过mm_struct描述的虚拟的地址空间,让每个进程都能访问一个完整独立的连续的虚拟地址,经过映射之后,实现物理内存上的离散存储,提高内存利用率。提高内存访问控制。

7.1 虚拟地址空间

Linux——(三)进程概念_第17张图片同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址

你可能感兴趣的:(linux,linux,僵尸进程,进程状态,孤儿进程,环境变量)