Linux进程概念

  • 基本概念

    • 课本概念: 程序的一个执行实例,正在执行的程序等。

    • 内核观点: 担当分配系统资源(CPU时间,内存)的实体。

  • 描述进程-PCB

    • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合

      • task_struct-PCB的一种

        • PCB实际上是对进程控制块的统称,在Linux中描述进程的结构体叫做task_struct。

        • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含进程的信息。

      • task_struct内容分类

        • 标示符: 描述本进程的唯一标示符,用来区别其他进程。

        • 状态: 任务状态,退出代码,退出信号等。

        • 优先级: 相对于其他进程的优先级。

        • 程序计数器(pc): 程序中即将被执行的下一条指令的地址。

        • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

        • 上下文数据: 进程执行时处理器的寄存器中的数据。

        • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

        • 记账信息: 可能包括处理器时间总和,使用的时钟总和,时间限制,记账号等。

        • 其他信息。

    • 操作系统将每一个进程都进行描述,形成了一个个的进程控制块(PCB),并将这些PCB以双链表的形式组织起来。

  

  • 查看进程

    • 通过系统目录查看

      • 根目录下有一个名为proc的系统文件夹。

      • 有些子目录的目录名为数字。数字其实是某一进程的PID,对应文件夹当中记录着对应进程的各种信息

      • 例: ls /proc/1 

    • 通过ps命令查看

      • 单独使用ps命令,会显示所有进程信息。

        • ps aux

      • ps命令与grep命令搭配使用,即可只显示某一进程的信息。

        • ps aux | head -1 && ps aux | grep proc | grep -v grep

    • 通过系统调用获取进程的PID和PPID

      • 通过使用系统调用函数,getpid和getppid即可分别获取进程的PID和PPID。

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

      • fork函数创建子进程

        • 在fork函数被调用之前的代码被父进程执行,而fork函数之后的代码,则默认情况下父子进程都可以执行。

        • 需要注意的是,父子进程虽然代码共享,但是父子进程的数据各自开辟空间(采用写时拷贝)

      • 使用if分流

        • fork函数的返回值:

          • 1、如果子进程创建成功,在父进程中返回子进程的PID,而在子进程中返回0。

          • 2、如果子进程创建失败,则在父进程中返回 -1。

        • 可以根据fork的返回值进行if分流,达到让父子进程各自完成对应任务的目的

  • Linux进程状态

    • 运行状态-R

      • task_struct处于运行队列中(排队中)/或者正在进行

      • 运行先后由操作系统调度

    • 阻塞状态

      • 等待非CPU资源就绪

    • 挂起状态

      • 内存快不足的时候,操作系统会将长时间不执行的进程代码和数据换出到磁盘

      • 此时进程的状态就叫挂起

    • 浅度睡眠状态-S

      • 可中断睡眠

      • 演示代码

        #include<stdio.h>
        
        #include <unistd.h>
        int main()
        {
            printf("正在运行......\n");
            sleep(50);
           
            return 0;
        }

        运行结果

      •  ps aux | head -1 && ps aux | grep test | grep -v grep

    • 深度睡眠状态-D

      • 不可以被中断

      • 不可以被唤醒

      • 磁盘睡眠

    • 暂停状态-T

      • 应用场景:调试,对进程发送暂停信号

      • kill -SIGSTOP 18209

        代码

      • #include<stdio.h>
        
        #include <unistd.h>
        int main()
        {
            while(1)
            {
                printf("hello\n");
            }
            return 0;
        }


        演示结果

    • 僵尸状态-Z

      • 是什么

        • 一个进程已经退出,但是害不允许被os释放,处于一个被检测的状态

        • 一般是父进程或者操作系统检测

      • 为什么

        • 维持这个状态,方便父进程或者OS回收

    • 死亡状态-X

      • 终止状态

  • 僵尸进程

  • 僵尸进程的危害

    • 僵尸进程的退出状态必须一直维持下去,因为它要告诉其父进程相应的退出信息。可是父进程一直不读取,那么子进程也就一直处于僵尸状态。

    • 僵尸进程的退出信息被保存在task_struct(PCB)中,僵尸状态一直不退出,那么PCB就一直需要进行维护。

    • 若是一个父进程创建了很多子进程,但都不进行回收,那么就会造成资源浪费,因为数据结构对象本身就要占用内存。

    • 僵尸进程申请的资源无法进行回收,那么僵尸进程越多,实际可用的资源就越少,也就是说,僵尸进程会导致内存泄漏。

  • 孤儿进程

    • 子进程在父进程之前退出

    • 由1号init进程领养,也由他回收

    • 代码演示

    • 演示结果

  • 进程优先级

    • 基本概念

      • 为什么有优先级

        • cpu是有限的,进程太多,需要通过某种方式竞争资源

      • 什么是优先级

        • 确定是谁应该先获得某种资源,谁后获得

          • 通过一些数据表明优先级

        • 老的优先级+nice值

    • 查看系统进程

      • UID:代表执行者的身份。

      • PID:代表这个进程的代号。

      • PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。

      • PRI:代表这个进程可被执行的优先级,其值越小越早被执行。

      • NI:代表这个进程的nice值。

    • PRI与NI

      • PRI代表进程的优先级(priority),通俗点说就是进程被CPU执行的先后顺序,该值越小进程的优先级别越高。

      • NI代表的是nice值,其表示进程可被执行的优先级的修正数值。

      • PRI值越小越快被执行,当加入nice值后,将会使得PRI变为:PRI(new) = PRI(old) + NI。

      • 若NI值为负值,那么该进程的PRI将变小,即其优先级会变高。

      • 调整进程优先级,在Linux下,就是调整进程的nice值。

      • NI的取值范围是-20至19,一共40个级别。

      • 注意: 在Linux操作系统当中,PRI(old)默认为80,即PRI = 80 + NI。

    • 查看进程优先级信息

      • ps -al

    • 通过top命令更改进程的nice值

    • 通过renice命令更改进程的nice值

    • 四个重要概念

      • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便有了优先级。

      • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。

      • 并行: 多个进程在多个CPU下分别同时进行运行,这称之为并行。

      • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

  • 环境变量

    • 基本概念

      • 一般是指在操作系统中用来指定操作系统运行环境的而一些参数

    • 常见环境变量

      • PATH

        • 指定命令的搜索路径

      • HOME

        • 指定用户的祝工作目录

      • SHELL

        • 当前shell,一般是/bin/bash

    • 查看环境变量的方法

      • env--查看所有环境变量

      • echo $NAME

    • 测试PATH

      • echo $PATH

      • 而系统就是通过环境变量PATH来找到ls命令

      • set PATH=$PATH:当前路径

    • 那可不可以让我们自己的可执行程序也不用带路径就可以执行呢?

      • 方式一:将可执行程序拷贝到环境变量PATH的某一路径下。

      • 方式二:将可执行程序所在的目录导入到环境变量PATH当中

    • 测试HOME

      • echo $HOME

    • 测试SHELL

      • echo $SHELL

    • 和环境变量相关的命令

      • echo
        • 显示某个环境变量值

      • export
        • 设置一个新的环境变量

      • env
        • 显示所有环境变量

      • unset
        • 清楚环境变量

      • set
        • 显示本地定义的shell变量和环境变量

    • 环境变量的组织方式

    • 通过代码获取环境变量

      • main的第三个变量

main函数的第三个参数接收的实际上就是环境变量表,我们可以通过main函数的第三个参数来获取系统的环境变量。

#include<stdio.h>

#include <unistd.h>
int main(int argc,char *argv[],char* envp[])
{
    //方式一
    int i=0;
    while(envp[i])
    {
        printf("envp[i]: %S\n",envp[i]);
        i++;
    }

    //方式二
    // //或者用一个变量来接收
    // extern char** environ;
    // int i=0;
    // while(environ[i])
    // {
    //     printf("%s\n",environ[i]);
    // }

  return 0;
}
    • 演示效果 
    • 通过系统调用获取环境变量

      • 通过代码获取到环境变量还需要对返回的字符串做接收,才能继续做后面的操作。实际上操作系统自己就有系统调用接口来获取环境变量

      • setenv函数--设置环境变量

      • getenv函数--获得环境变量

      • 代码演示
#include<stdio.h>
#include<stdlib.h>

int main()
{
    printf("HOME: %s\n",getenv("HOME"));
    return 0;
}
      • 演示效果 
  • 程序地址空间

  • 代码演示

#include<stdlib.h>
#include<stdio.h>

int g_val=10;
int g_uval;
int main(int argc,char* argv[],char* envp[])
{
    printf("代码区:%p\n",main);
    char* str="abcde";
    printf("只读常量区: %p\n",str);
    printf("初始化数据区: %p\n",&g_val);
    printf("未初始化数据区: %p\n",&g_uval);

    int *p=(int*)malloc(10);
    printf("堆区: %p\n",p);
    printf("栈区: %p\n",&p);
    printf("###############\n");
    int i=0;
    for(i=0;i<argc;i++)
    {
        printf("命令行参数:%p\n",argv[i]);
    }

    while(envp[i])
    {
        printf("环境变量: %p\n",&envp[i]);
        i++;
    }

return 0;
}
  • 演示效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值