进程概念+状态+优先级

一、计算机硬件知识

(1)冯·诺依曼体系

       a:运算器+控制器=cpu
       b:输入设备和输出设备属于外设(除cpu和内存外的都是外设)
       c:存储器=内存(不包括硬盘等)
       d:对于数据信号,外设只能直接和存储器打交道, cpu也只能直接和存储器打交道(cpu不能直接与外设联系)
       e:以在扣扣上发送消息为例,步骤为:
       发送方键盘(发送方输入设备)->发送方内存->qq封装处理消息(cpu)->返回到发送方内存->由发送方网卡(发送方输出设备)进行网络发送->接         收方网卡(接收方输入设备)接收消息->接收方内存->解包(cpu)->返回到接收方内存->接收方显示屏(输出设备)显示

二、操作系统

(1)OS:管理计算机软硬件资源的软件。    
         OS是一个基本的程序集合,笼统来说包括内核(进程管理、内存管理、文件管理、驱动管理)与其他程序(库函数、shell程序等)。
(2)     

        管理者:校长                                            
        中间人(执行者):辅导员(不做管理决策)
        被管理者:学生
         【要管理好,管理者和被管理者可以不直接打交道】
         【管理者通过数据做数据决策】

        管理者:操作系统
        中间人(执行者):驱动程序
        被管理者:硬盘
        【不直接交流,通过OS采集到的硬件数据,而OS采集的硬盘数据由驱动程序提供】

(3)管理层次图如下:

(4)OS的定位
        对下进行软硬件资源的管理 + 对上提供良好的执行环境
(5)OS对上只提供各种接口,这些接口称为系统调用。
        不同于库函数调用,系统调用要求对系统理解较深,库是基于此又开发的一层,便于降低调用要求。
        所以系统接口和库函数接口是上下层关系。

三、进程概念

先把每个学生 描述(用结构体存其数据)起来,再把学生的描述信息传给管理系统(即把学生的描述信息 组织起来)。
(1)基本概念
        进程是程序的一个执行实例、正在执行的程序等。对于内核来说,进程是担当分配系统资源(CPU时间、内存)的实体。
(2)进程描述——PCB
        PCB:进程被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。 linux系统下的PCB是:task_struct。
        【每个进程都有一个结构体,再在每一个结构体内添加一个结构体指针,由此形成一个链表,OS通过该链表管理进程】
        【描述进程的结构体称为PCB】
        【管理进程其实就是管理进程的PCB】
(3)所以内存中有:OS、一堆进程、与进程对应的一堆PCB
(4)进程与程序的区别:
        在硬盘上放着的程序,一旦进入内存就是进程。
        程序一进入内存,OS就会给其建立PCB维护起来。
(5)task_struct 的内容分类
  • 标识符:  描述本进程的唯一标识符,用来区别其他进程。  PID
  • 状态:  任务状态,退出代码,退出信号等。
  • 优先级:  相对于其他进程的优先级。
  • 程序计数器:  程序中即将被执行的下一条指令的地址。
  • 内存指针:  包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据:  进程执行时处理器的寄存器中的数据(休学例子、要加图CPU、寄存器)。
  • I/O状态信息:  包括显示的I/O请求,分配给进程是I/O设备和被进程使用的文件列表。
  • 记账信息:  可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息。
(6)进程的切换        
       被中断进程的信息保存在内存中,保存在内存中该进程的PCB中。
(7) 进程的id: PID   唯一标识符
(8)查询进程:
        proc   【进程的信息可以通过 /proc 系统⽂文件夹查看     如:要获取PID为1的进程信息,你需要查看 /proc/1 这个⽂文件夹】
        ps    【加参数aux将所有进程的信息展示出来】    ps aux | grep ‘5962’ ->查询PID为5962的进程,grep为管道
        系统调用    【通过系统调用同样可以获取进程的PID】getpid()获取当前进程的pid     getppid()获得父进程的pid
(9) 所有进程都是bash
(10)终止进程
        ctrl+c
        kill       [kill -9 6233]  6233为要杀掉进程的PID
(11)创建进程
       让程序跑起来
       fork()
(12)关于fork()
       fork()可创建子进程
        fork()有两个返回值 ,分别为:给父进程返回子进程的PID、给子进程返回0。   因为孩子的父亲只有一个,而父亲的孩子不一定只有一个,所以子进程给父进程返回自己的PID、给自己返回0。
       【关于为什么会有两个返回值:因为当一个程序要返回时说明已经运行完成,子进程已经存在,此时运行返回语句,会因为子进程和父进程的代码共用性而运行两次。返回值的接收会触发写时拷贝(见(13))】
       fork()之后,子进程和父进程共享代码   (一个执行另一个也执行),效果见下图;但两者的数据私有,即数据各自保存
eg:   
对于下面的程序,    
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
    fork();
    printf("hello world!,pid:%d,ppid:%d\n",getpid(),getppid());
    sleep(1);
    return 0;
}
运行结果为:
[root@localhost 1_class]# ./test_static
hello world!,pid:6367,ppid:5962
hello world!,pid:6368,ppid:6367    
【显然,下面的显示结果为子进程的显示结果,fork()得到的子进程的PID为:6368。其创建步骤为:bash创建PID为6367的父进程,父进程创建PID为6368的子进程。】
(13)写时拷贝
       父子有任何一个进程尝试写入某程序时,OS会为其重新开辟一个空间让其写入。  只有写入时才会单独拷贝,平时共用,可节约空间。
(14)虽然父进程与子进程共享代码,但通常会为父进程和子进程分配不同的代码块。即将程序分流后让父进程和子进程各执行不同的代码块。
如:
#include <stdio.h>
#include <sys/type.h>
#include <unistd.h>
int main()
{
    pid_t id=fork();
    if(id==0)  //子进程
    {
         while(1)
         {
            printf("child do thing 1……,pid:%d,ppid:%d\n",getpid(),getppid());
            sleep(1);
        }
     }
    else if(id>0)    //父进程
    {
        while(1)
         {
            printf("father do thing 2……,pid:%d,ppid:%d\n",getpid(),getppid());
            sleep(3);
        }
    }
    else
    {
        perror("fork");
    }
    return 0;
}
//将子进程与父进程的任务利用if语句分割开来
(15)fork()之后子进程和父进程谁先运行并不确定,完全由调度器决定。

四、进程状态

1、状态有哪些?
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
  • R运⾏行状态(running): 并不意味着进程⼀一定在运⾏行中,它表明进程要么是在运⾏行中要么在运⾏行队列里。
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这⾥里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停⽌止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停⽌止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运⾏行。
  • X死亡状态(dead):这个状态只是⼀一个返回状态,你不会在任务列表⾥里看到这个状态。
【暂停和睡眠的区别:sleep做事情了,stop没有做事情,什么都没做。】
【sleep为浅度睡眠,可唤醒;D状态为深度睡眠状态,不可强制唤醒。S状态的进程可以被杀死,D状态不能被杀死】
【进程状态信息后面的+号表示是前台运行,没有+说明是后台运行】
【R状态不一定占CPU,但占CPU的一定是R状态】
2、进程状态切换图:

3、僵尸进程
  • 僵死状态(Zombies)是⼀一个⽐比较特殊的状态。当进程退出并且⽗父进程(使⽤用wait()系统调⽤)没有读取到⼦子进程退出的返回代码时就会产⽣生僵死(⼫尸)进程
  • 僵死进程会以终⽌止状态保持在进程表中,并且会⼀一直在等待⽗父进程读取退出状态代码。
  • 所以,只要⼦子进程退出,⽗父进程还在运⾏行,但⽗父进程没有读取⼦子进程状态,⼦子进程进⼊入Z状态
僵⼫尸进程危害:
  • 进程的退出状态必须被维持下去,因为他要告诉关⼼心它的进程(⽗父进程),你交给我的任务,我办的怎么样了。可⽗父进程如果⼀直不读取,那⼦子进程就⼀直处于Z状态?是的!
  • 维护退出状态本⾝身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态⼀直不退出,PCB⼀直都要维护?是的!
  • 那⼀个⽗父进程创建了很多⼦子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本⾝身就要占⽤用内存,想想C中定义⼀个结构体变量(对象),是要在内存的某个位置进⾏行开辟空间!
  • 内存泄漏?是的!
4、孤儿进程
    父进程如果提前退出,那么子进程就称之为“孤儿进程”
    孤儿进程会被1号init进程领养,也就是说会由1号进程进行回收。
    父进程退出后为什么没有成为僵尸进程?因为父进程的父进程bash会立刻对死掉的父进程进行回收。

五、进程的优先级
1、重要的身份
  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生⽽而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值
2、关于进程优先级PRI
    cpu资源分配的先后顺序,就是指进程的优先权(priority)。
    优先权高的进程有优先执行权利。
    配置进程优先权对多任务环境的linux很有用,可以改善系统性能。还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
3、 NI代表nice值,表示进程可被执行的优先级的修正数值
    默认优先级的值为80,默认nice值为0     优先级越低越晚执行   
    修改进程优先级的命令:
    nice
    renice
    【开始执⾏行程序就指定nice值: nice -n -5 ./test】
   【 renice -5 -p 5200 //PID为5200的进程nice设为-5】
    用top命令更改已存在进程的nice:进入top后按“r”–>输入进程PID–>输入nice值
4、其他概念
  • 竞争性: 系统进程数⺫⽬目众多,⽽而CPU资源只有少量,甚⾄至1个,所以进程之间是具有竞争属性的。为了⾼高效完成任务,更合理竞争相关资源,便具有了优先级
  • 独⽴立性: 多进程运⾏行,需要独享各种资源,多进程运⾏行期间互不干扰
  • 并⾏行: 多个进程在多个CPU下分别,同时进⾏行运⾏行,这称之为并⾏行
  • 并发: 多个进程在⼀一个CPU下采⽤用进程切换的⽅方式,在⼀一段时间之内,让多个进程都得以推进,称之为并发

















猜你喜欢

转载自blog.csdn.net/gunqu_d/article/details/80528952