Linux进程概念

Linux系统编程阶段:使用Linux系统提供的接口完成指定功能程序的编写

进程概念:冯诺依曼体系结构,操作系统,进程概念,进程状态,环境变量,程序地址空间

  1. 冯诺依曼体系:现代计算机的硬件体系结构(规定了现代计算机应该具有哪些硬件单元)
    硬件单元:输入设备-键盘,输出设备-显示器,存储器-内存条(内存-内存条,外存-硬盘),运算器,控制器(运算器+控制器=中央处理器cpu;主频:2.5GHz–每秒钟cpu能够处理多少指令)
    所有设备都是围绕存储器工作的,存储器是作为中间的数据缓冲而存在的
    硬件结构决定了软件行为,程序运行,会被加载到内存中

  2. 操作系统:Linux
    组成:内核+应用
    定位:计算机上搞管理的软件,管理计算机上的软硬件资源

    系统调用接口:操作系统提供的用户访问系统内核的接口
    库函数与系统调用接口的关系:库函数实际上就是对系统调用接口进行的一层封装后的接口

  3. 进程概念:进程就是运行中的程序
    pcb(进程控制块):程序运行的描述
    通过程序的运行描述,操作系统就可以调度哪个程序可以占用cpu去运行指令(cpu的分时机制:多任务操作系统中使用分时机制实现多任务并发处理,时间片:cpu调度运行程序的时间段,时间片过后,就该切换调度下一个进程了)。要运行哪个程序,则操作系统找到对应程序的pcb,在pcb上取得程序的运行所需信息,加载到cpu上,cpu就开始运行这个程序了。一个程序可以作为多个进程的运行程序。
    对于操作系统来说,进程就是一个程序运行的动态描述(即pcb进程控制块,在linux下是一个task_struct结构体),通过这个描述,操作系统可以进行程序的调度运行管理。即实际上对于操作系统来说,进程就是pcb。
    描述信息:内存指针,上下文数据,程序计数器,进程ID-pid,IO信息,进程优先级,进程状态,记账信息

    并发:一种轮询处理的方式
    并行:同时运行

    进程的简单操作:
    创建进程:创建进程实际上就是创建了一个task_struct结构体
    创建进程的接口:pid_t fork(void)—通过复制调用这个接口的进程(父进程),创建一个新的进程(子进程)。
    将父进程整体复制,但是因为程序计数器保存的位置是创建子进程成功之后的指令,因此复制过来之后,子进程从这里开始运行。
    返回值:对于父进程会返回创建的子进程的pid,对于子进程会返回0

    getpid():返回调用进程的进程ID(PID)
    getppid():返回调用进程的父进程的进程ID。
    ps -ef / -aux:查看所有进程的信息

    进程创建代码:

 #include <stdio.h>
 #include <unistd.h>
 
 int main()
 {
   pid_t pid = fork();
   if(pid < 0)
   {
     //出错了
   }
   else if(pid == 0)
   {
     printf("子进程id=%d\n",getpid());
   }
   else
   {
     printf("父进程id=%d\n",getpid());
   }
   while(1) sleep(1);                                                                                            
   return 0;
 }

运行结果
在这里插入图片描述
通过ps -ef查看的结果
在这里插入图片描述

  1. 进程状态:用于操作系统对于进程的管理(什么状态该对进程进行什么样的操作)
    运行态,就绪态,阻塞态
    Linux中的进程状态:
    状态后边的+,表示这个进程是一个前台进程(当前占据终端的进程)
    运行态(R):正在运行或者轮转到时间片能够运行统称为运行态
    可中断休眠态(S):可以被中断的休眠状态(满足唤醒条件,或者休眠被中断则进入运行态)
    不可中断休眠态(D):不能被中断的休眠状态(满足唤醒条件之后才会进入运行态)
    停止态(T):程序停止运行的状态(依然会被调度,但是什么都不做)
    死亡态(X):这个状态只是一个返回状态,不会在任务列表里看到这个状态
    僵尸态(Z):进程已经退出不再调度了,但这个进程的资源还没有被完全释放,等待处理的一种状态

    僵尸进程:处于僵尸态的进程,即是一种退出了但资源还没有完全被释放的进程。
    产生的原因:子进程先于父进程退出,但是父进程没有关注到子进程的退出,因此系统不会完全释放子进程的资源,这个子进程进入僵尸状态。子进程退出后,在进程pcb中保存了自己的退出返回值,在父进程没有关注处理的情况下,pcb资源是不会被释放的。
    危害:资源泄漏(一种是pcb所占的内存资源一直无法被回收,另一种是一个用户所能创建的进程数量是有限制的—可通过ulimit -a查看)
    解决方案:
    处理:退出父进程
    避免:进程等待

    创建僵尸进程:

	int main()
 {
   pid_t pid = fork();
   if(pid < 0)
   {
     //子进程复制了父进程,因此往后的代码父子进程都会运行,
 		//但是因为返回值的不同而进入不同的if
     //出错了
   }
   else if(pid == 0)
   {
     //子进程---对于子进程返回值是0
     printf("子进程id=%d\n",getpid());   
     sleep(5);
     exit(0);//退出进程---谁调用就退出谁
   }
   else
   {                                                                                                             
     //父进程---对于父进程返回的是子进程的pid,因此返回值是大于0的
     printf("父进程id=%d\n",getpid());
   }
   while(1) sleep(1);
   return 0;
 

通过ps -aux查看僵尸子进程:
在这里插入图片描述

孤儿进程:父进程先于子进程退出,子进程就会成为孤儿进程,运行在后台,父进程成为1号进程(早期名字叫init进程,后期叫systemd)

创建孤儿进程:

 int main()
 {
   pid_t pid = fork();
   if(pid < 0)
   {
     //子进程复制了父进程,因此往后的代码父子进程都会运行,但是因为返回值的不同而进入不同的if
     //出错了
   }
   else if(pid == 0)
   {
     //子进程---对于子进程返回值是0
     printf("子进程id=%d\n",getpid());
   }
   else
   {
     //父进程---对于父进程返回的是子进程的pid,因此返回值是大于0的
     printf("父进程id=%d\n",getpid());
     sleep(5);                                                                                                                    
     exit(0);//退出进程---谁调用就退出谁
   }
   while(1) sleep(1);
   return 0;
 }

通过ps -ef查看孤儿进程以及其父进程
在这里插入图片描述
五秒后父进程退出,孤儿进程的父进程变为1号进程
在这里插入图片描述

守护进程(精灵进程):特殊的孤儿进程,运行在后台,脱离与终端的关系,脱离登录会话

  1. 环境变量:也是一种变量,是一种保存系统运行环境参数的变量;便于运行环境参数的配置,进程之间的数据通信(子进程的环境变量就是从父进程而来的)

    命令操作:
    env—查看当前运行环境中的所有环境变量
    set—查看当前运行环境中的所有变量
    export—声明或设置一个环境变量
    echo—查看指定变量(也可通过echo $PATH查看环境变量)
    unset—删除变量

    PATH:程序运行的默认搜索路径—在命令行终端中输入命令名称可以直接执行对应名称的命令程序,实际上是因为shell捕捉到输入的命令名称之后,会去PATH环境变量指定的路径下去找这个程序,找到了就运行,找不到就报命令没有找到的错误。

    环境变量接口:
    char* getenv(const char* name)—通过名称获取值;
    int setenv(const char* name, const char* value, int overwrite) / int putenv(char* string)—设置环境变量

    代码操作:
    getenv()、extern char** environ、main(int argc, char* argv[], char* env[])
    main函数有三个参数—程序运行参数的个数,程序运行参数字符串地址,环境变量的字符串地址

    shell中运行的程序,父进程都是shell,shell中运行的进程都是shell的子进程,它们的环境变量都是通过shell设置的,每个shell终端都是一个运行环境,不同的终端拥有不同的shell,每个shell都拥有它自己设置的环境变量,因此在不同的终端中运行环境可能不同。

  2. 程序地址空间:
    地址:通常所说的地址,都是内存的地址,是内存单元的编号
    而在进程中,程序访问的这些地址(变量地址…)实际上是一个假地址—虚拟地址,我们所说的程序地址空间实际上叫做进程的虚拟地址空间。虚拟地址空间实际上是系统给进程所描述的一个假的地址空间,是一个mm_struct结构体。并且每个进程都有自己独立的虚拟地址空间,也就是有自己的mm_struct内存描述。进程访问的都是虚拟地址,访问内存数据的时候,先将虚拟地址转换为物理地址然后访问。

    系统为每个进程都描述一个完整的,连续的,线性的虚拟地址空间,实际物理内存用的时候再给进程分配。这样的话,对于每个进程来说,看起来都有一块完整的,连续的内存可以使用。
    给每个进程虚拟一个地址空间,让进程访问完整连续的地址,但是这些虚拟地址在使用的时候通过页表映射一块物理内存地址,进行访问物理内存。通过映射这种方式,实现了数据在物理内存上的离散式存储,提高内存利用率。

    虚拟内存空间:是系统为每个进程通过mm_struct结构体虚拟的一个地址空间,使用虚拟地址空间的目的是为了让进程能够访问一块连续的,完整的地址。并且经过页表映射到物理内存之后,可以实现数据在物理内存上的离散式存储,提高内存利用率,并且在页表中可以进行内存访问控制。

    虚拟地址是如何通过页表获取到物理地址的呢?
    内存管理方式:
    分段式内存管理:将地址空间分为多段(代码段、数据段…),便于编译器进行地址管理。分段式虚拟地址组成:段号+段内的地址偏移量;在系统中有一个段表:一个个段表项(段号+物理内存起始地址)

    分页式内存管理:将地址空间分为多个小块(页),实现数据的离散式存储,提高内存利用率,提高内存安全访问控制。分页式虚拟地址组成:页号+页内偏移;在系统中有一个页表(页号,物理内存块起始地址,权限控制,缺页中断位…)
    若4G内存(232),内存页大小为4K(212),则有220个内存页,因此在32位内存地址下,高20位就是页号,低12位就是页内偏移。

    段页式内存管理:将虚拟地址空间进行分段,在每个分段内进行分页式管理,集合了分段分页的优点进行内存管理。

    缺页中断:当我们通过虚拟地址访问物理内存的时候,发现数据没有在物理内存中。
    原因:内存置换(当物理内存不够用的时候,将物理内存中不活跃的数据,交换到磁盘的交换分区上,腾出内存用于新的数据处理)
    内存置换算法:LRU—最久未使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值