Linux——初识进程

1.冯·诺依曼体系结构

日常生活照我们常见的计算机,如笔记本,还有我们不常见的计算机,如服务器,大部分都遵循冯·诺依曼体系,该体系结构示意图如下:
在这里插入图片描述
我们所认识的计算机都是由一个个的硬件组组成:

  • 输入单元:包括键盘、鼠标、扫描仪等
  • 输出单元:显示器、打印机等
  • 中央处理器(CPU):含义运算器和控制器等

关于冯诺依曼体系,强调:

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

2.操作系统(Operator System)

概念:任何计算机系统都包含一个基本的程序结构,称为操作系统(OS),其包括:

  • 内核(进程管理、内存管理、文件管理、驱动管理)
  • 其他程序(如函数库等)

操作系统存在的意义

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

操作系统的定位:在整个计算机软硬件架构中,操作系统是一款搞管理的软件。

3.初识进程

  • 查看进程信息:ls /proc/
    在这里插入图片描述* 每个进程都有自己的PID,要获得自己的PID:getpid() 方法
  • 获得父进程的PID:getppid()方法
  • Linux下创建一个子进程:fork()方法

使用fork创建一个子进程,它的数据和代码是从父进程那里继承过来的,子进程的PCB大部分内容和父进程一样
父子进程代码共享,数据却各自私有一份(写时拷贝
返回值问题:fork后,子进程返回0,父进程返回子进程的PID(一个父进程有多个子进程,返回PID才能准确锁定)

4.进程状态

  • R运行状态(running):进程要么在运行要么在等待队列
  • S睡眠状态(sleeping):进程在等待事件完成(可中断睡眠)
  • D磁盘休息状态(Disk sleep):此时进程通常会等待IO的结束(不可中断睡眠)
  • T停止状态(stopped):通过SIGSTOP信号开暂停运行进程,通过SIGCONT继续运行该进程
  • X死亡状态(dead):只是一个返回状态,不会出现在任务列表中
  • Z僵尸状态(zombie):子进程运行终止后,PCB从内存中移除,而他的进程描述符还在,要告知父进程自身状态,这时进程就处于僵尸状态,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息,在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中,从而会造成内存泄漏

孤儿进程:父进程如果提前退出,那么子进程就被称为“孤儿进程”,孤儿进程会被1号init进程领养,当然了,init进程会回收它

5.进程优先级

在Linux或者Unix操作系统中,用ps -l命令会类似输出一下内容:
在这里插入图片描述
修改进程优先级:
nice:启动进程前指定nice值:nice -n -5 ./test
renice:调整已经存在进程的nice:renice -5 -p 5200 //PID为5200的进程nice设为-5

6.环境变量

环境变量:在操作系统中用来指定操作系统运行环境的一些参数

  • PATH:指定命令的搜索路径
  • HOME:指定用户的主工作目录(用户登录Linux系统时默认的目录)
  • ISTSIZE:指保存历史命令记录的条数
  • SHELL:当前Shell

查看环境变量:echo $NAME //NAME:环境变量名称

7.进程的虚拟地址空间

在这里插入图片描述

8.进程的创建与终止

8.1.fork函数:pid_t fork(void);

进程调用fork后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统程序列表中
  • fork返回,开始调度器调度

fork返回值

  • 子进程返回0
  • 父进程返回的是子进程PID

fork的写时拷贝:通常,父子进代码共享,父子在不写入时,数据也是共享的,但是当任意一方视图写入时,便以写时拷贝的方式各自一份副本

fork常规用法:

  • 一个父进程希望复制自己,使子进程同时执行不同的代码
  • 一个进程要执行不同的程序

fork调用失败原因:

  • 系统中有太多进程
  • 实际用户的进程数超过限制

8.2.进程终止

进程的退出场景

  • 代码运行完毕,结果正确
  • 代码运行完毕,结果不正确
  • 代码异常终止

进程常见退出方法

  • 正常终止(可以通过echo $?查看进程退出码)
    (1)从 main方法返回
    (2)调用exit
    (3)_exit
  • _exit函数:void _exit(int status); //status定义了进程终止状态,父进程通过wait来获取该值
  • exit函数:void exit(int status);
    exit函数做了如下工作:(1)执行用户通过atexit或on_exit定义的清理函数工作
    (2)关闭所有打开的流,所有的缓存数据均被写入
    (3)调用_exit
  • 异常退出
    ctrl + c,信号终止

8.3.进程等待

进程等待的必要性

  • 子进程退出,如果父进程不管不顾,就可能造成僵尸进程,进程一旦进入僵尸状态那就刀枪不入,杀人不眨眼的“kill -9”也无能为力,毕竟没有谁能够杀掉一个“已经死掉”的进程,那么会进一步造成内存泄漏
  • 父进程委派给子进程的任务完成的如何我们也该知道
  • 父进程通过进程等待的方式,回收子进程资源,并且获得子进程退出信息

进程等待的方法
(1)wait
(2)waitpid

pid_t wait(int* status);

  • 返回值:返回被等待进程的PID,失败返回-1
  • 参数:输出型参数,获取进程退出状态,不关心则可以设置为NULL
    pid_t waitpid(pid_t pid,int* status,int options);
  • 返回值:(1)当正常返回时waitpid返回收集到的子进程的进程ID
    (2)如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0
    (3)如果调用中出错则返回-1,这是errno会被设置为相应的值以指示错误的存在
  • 参数:(1)pid:pid为-1时等待任意一个子进程,与wait等效;pid > 0时,等待其进程ID等于pid的进程
    (2)status:WIFEXITED,查看进程是否正常退出,正常退出则为真
    WEXITSTATUS,若WIFEXITED非0,提取子进程退出码
    (3)options:WNOHANG,若pid指定的子进程没有结束,则waitpai函数返回0不予以等待,若正常结束返回该子进程的ID
  • 如果子进程已经退出,调用wait/waitpid时,会立即返回子进程退出信息并释放资源
  • 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
  • 如果不存在该子进程,则立即出错返回

获取子进程status

  • wait和waitpai方法都有一个status参数,该参数是一个输出型参数,由操作系统来填充
  • 如果传递NULL,表示不关心子进程的退出状态信息
  • 否则操作系统会根据该参数,将子进程的退出信息返回给父进程
  • status不能简单的当做整型来看,可以当做位图来看待,具体细节如下图:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/LiLiLiLaLa/article/details/87886093
今日推荐