M的编程备忘录之Linux——进程概念

目录

1、冯诺依曼体系       ​

2、操作系统

2.1、概念

2.2、设计的目的

2.3、定位

3、进程

3.1、基本概念

3.2、描述进程-PCB

3.2.1、tack_struct——PCB的一种

3.2.2、task_struct内容分类

3.3、组织进程

3.4、查看进程

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

3.6、通过系统调用创建进程——fork初始

 3.7、进程状态

3.8、Z——僵尸状态

 3.9、孤儿进程

4、进程优先级

4.1、概念

4.2、查看系统进程     ​

4.3、PRI和NI

4.4、 查看进程优先级的命令

4.5、其他

5、环境变量

5.1、概念

5.2、常见环境变量

5.3、和环境变量相关命令

5.4、环境变量组织方式

5.5、获取环境变量

5.5.1、命令行第三个参数

5.5.2、通过第三方变量environ获取

5.5.3、getenv

6、程序地址空间

7、内核进程调度队列

​7.1、优先级

7.2、活动队列        

7.3、过期队列         

7.4、 active指针和expired指针


1、冯诺依曼体系       

                输入设备:键盘、鼠标、扫描仪、写板等
                中央处理器(cpu):含有运算器和控制器
                输出单元:显示器、打印机等

        注意

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

2、操作系统

2.1、概念

        任何计算机系统都包含一个基本的程序集合,称为操作系统。

                大概包括:

                        1、内核(进程管理、内存管理、文件管理、驱动管理)

                        2、其他程序

2.2、设计的目的

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

2.3、定位

        这是一款纯正的“搞管理”的软件

3、进程

3.1、基本概念

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

3.2、描述进程-PCB

3.2.1、tack_struct——PCB的一种

        在Linux中描述进程的结构体叫做task_struct。
        task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息

3.2.2、task_struct内容分类

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

        其他信息

3.3、组织进程

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

3.4、查看进程

        进程的信息可以通过 /proc 系统文件夹查看

        循环打印进程信息脚本:while :; do ps ajx | head -1 && ps ajx |grep 进程名 |grep -v grep; sleep 1; echo "################"; done

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

        PID:进程id
        PPID:父进程id

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
 printf("pid: %d\n", getpid());
 printf("ppid: %d\n", getppid());
 return 0;
}

3.6、通过系统调用创建进程——fork初始

        fork有两个返回值
        父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
  pid_t id=fork();
  if(id==0)
  {
     
    printf("我是子进程,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid());
    sleep(1);
  }
  else
  {
    printf("我是父进程,我的pid是:%d,我的父进程是:%d\n",getpid(),getppid());  
    sleep(1);
  }  
  return 0;
}

 3.7、进程状态

        R运行状态: 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
        S睡眠状态: 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠)。
        D磁盘休眠状态:有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
        T停止状态: 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
        X死亡状态:这个状态只是一个返回状态,你不会在任务列表里看到这个状态

3.8、Z——僵尸状态

         僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程,僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
  pid_t id=fork();
  if(id==0)
  {
    int cnt=5;
    while(cnt)
    {
      printf("我是子进程,我还剩下%d秒\n",cnt--);
      sleep(1);
    }
    printf("我是子进程,我已经僵尸了,等待被检测\n");
    exit(0);//子进程退出
  }
  else 
  {
    while(1)//父进程一直循环
    {
      sleep(1);
    }
  }
  return 0;
}

 3.9、孤儿进程

        父进程先退出,子进程就称之为“孤儿进程” ,孤儿进程被1号init进程领养,有init进程回收。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
  pid_t id=fork();
  if(id==0)
  {
    int cnt=5;
    while(1)
    {
      printf("我是子进程,我还剩下%d秒\n",cnt--);
      sleep(1);
    }
    exit(0);
  }
  else 
  {
    int cnt=3;
    while(cnt)
    {
      printf("我是父进程,我剩下%d秒",cnt--);
      sleep(1);
    }
    exit(0);
  }
  return 0;
}

4、进程优先级

4.1、概念

        cpu资源分配的先后顺序,就是指进程的优先权(priority)。
        优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
        还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

4.2、查看系统进程     

        UID : 代表执行者的身份
        PID : 代表这个进程的代号
        PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
        PRI :代表这个进程可被执行的优先级,其值越小越早被执行
        NI :代表这个进程的nice值,其表示进程可被执行的优先级的修正数值

4.3、PRI和NI

        PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。        
        调整进程优先级,在Linux下,就是调整进程nice值,nice其取值范围是-20至19,一共40个级别,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化

4.4、 查看进程优先级的命令

        输入top

        进入top后按“r”–>输入进程PID–>输入nice值

4.5、其他

        竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
        独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
        并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
        并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

5、环境变量

5.1、概念

        环境变量:一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

5.2、常见环境变量

        PATH : 指定命令的搜索路径
        HOME : 指定用户的主工作目录
        SHELL : 当前Shell,它的值通常是/bin/bash

5.3、和环境变量相关命令

        1. echo: 显示某个环境变量值

        2. export: 设置一个新的环境变量
        3. env: 显示所有环境变量
        4. unset: 清除环境变量
        5. set: 显示本地定义的shell变量和环境变量

5.4、环境变量组织方式

        每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串

5.5、获取环境变量

5.5.1、命令行第三个参数

#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
     int i = 0;
     for(; env[i]; i++)
     {
         printf("%s\n", env[i]);
     }
     return 0;
}

5.5.2、通过第三方变量environ获取

#include <stdio.h>
int main(int argc, char *argv[])
{
     extern char **environ;
     int i = 0;
     for(; environ[i]; i++)
     {
         printf("%s\n", environ[i]);
     }
     return 0;
}
//libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。

5.5.3、getenv

#include <stdio.h>
#include <stdlib.h>
int main()
{
     printf("%s\n", getenv("PATH"));
     return 0;
}

6、程序地址空间

        我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理OS必须负责将虚拟地址转化成物理地址

7、内核进程调度队列

        一个CPU拥有一个runqueque

 7.1、优先级

        普通优先级:100~139
        实时优先级:0~99

7.2、活动队列        

        时间片还没有结束的所有进程都按照优先级放在该队列
        nr_active: 总共有多少个运行状态的进程
        queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级。
        从该结构中,选择一个最合适的进程,过程是:
                1. 从0下表开始遍历queue[140]
                2. 找到第一个非空队列,该队列必定为优先级最高的队列
                3. 拿到选中队列的第一个进程,开始运行,调度完成!
                4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
        bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率

7.3、过期队列         

        过期队列和活动队列结构一模一样
        过期队列上放置的进程,都是时间片耗尽的进程
        当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算

7.4、 active指针和expired指针

        active指针永远指向活动队列
        expired指针永远指向过期队列
        可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。 在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值