目录
前言:操作系统简介
概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(os)。笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)
狭义上来说,操作系统只是操作系统的内核。
设计目的
- 与硬件交互,管理所有的软硬件资源
- 为用户程序(应用程序)提供一个良好的执行环境
具体来说,有以下几个目的:
- 资源管理:确保cpu、内存、外设等资源被有效分配和调度,同时通过抽象层简化硬件复杂性。
- 用户界面:提供gui或cli,实现用户与系统直观交互,支持多用户环境。
- 程序执行:管理进程生命周期,实现内存虚拟化,支持程序并发运行。
- 数据管理:通过文件系统组织数据,实施访问控制保障数据安全。
- 设备支持:集成设备驱动,优化输入输出,确保硬件兼容性。
- 系统安全:实施安全措施,保护系统免受攻击,维护数据安全。
- 可移植与兼容:支持跨平台运行,确保软件兼容性,促进应用生态发展。
理解
在整个计算机软硬件架构中,操作系统的定位是:一款专门用于“管理”的软件 。
怎么理解这个“管理”?
- 管理的例子
- 描述被管理对象
- 组织被管理对象
总的来说就是:
- 描述起来,用struct结构体
- 组织起来,用链表或其他高效的数据结构
那么操作系统对进程的管理就是先把进程描述起来,再把进程组织起来!
进程:程序的执行之魂
进程,简而言之,是程序在计算机中的一次执行实例,是系统资源(如cpu时间、内存)的分配实体。linux中,进程以task_struct
(进程控制块,pcb)的化身形式存在内存中,存储着进程的全息:标识符、状态、优先级、程序计数器、内存指针、i/o状态、记账信息等。每一个进程,皆是task_struct
链表的一员,是linux内核管理进程的基石。
基本概念
- 课本概念(狭义):程序的一个执行实例,正在执行的程序等
- 内核观点(广义):担当分配系统资源(cpu时间,内存)的实体。
进程和程序的联系与区别
- 程序(program):程序是指由一组有序的计算机指令组成的一段可以在计算机上运行的代码。它是静态的,即指令的集合本身不随时间变化,也不具有执行的能力,直到被加载到内存中并由操作系统调用执行。程序是计算机编程的基本单位,用于实现特定的功能或解决特定的问题。
- 进程(process):进程是程序在一个数据集合上的运行过程,是系统进行资源分配和调度的一个独立单元。进程是动态的,它包含了程序计数器、寄存器的当前值以及内存的状态(如程序代码和数据的存储空间、程序控制块等)。进程是程序执行的具体实例,它反映了程序在执行过程中的状态变化。
描述进程-pcb
task_struct的内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图cpu,寄存器]。
- i/o状态信息: 包括显示的 i / o 请求,分配给进程的 i/o 设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
在linux中,进程 = 内核task_struct结构体 + 程序的代码和数据。
进程的标识符
进程id (pid): 标识进程的一个非负整型数。
父进程id (ppid) : 任何进程( 除 init 进程)都是由另一个进程创建,该进程称为被创建进程的父进程,对应的进程id称为父进程id(ppid)。如,a 进程创建了 b 进程,a 的进程号就是 b 进程的父进程id。
获取进程id和查看进程
getpid函数(获取进程id)
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
getppid函数(获取父进程id)
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
查看进程 : ps ajx
进程状态
我们可以先看看linux内核源代码是怎么描述进程(任务)的状态的:
/*
* the task state array is a strange "bitmap" of
* reasons to sleep. thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
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):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
五态模型:
状态转换
- 新建态 → 就绪态:当操作系统完成了进程创建的必要操作,并且当前系统的性能和内存的容量均允许时,进程将从新建态转换为就绪态。
- 就绪态 → 运行态:当cpu空闲时,操作系统的进程调度器会选中一个就绪进程,将其状态转换为运行态,并分配cpu资源给该进程执行。
- 运行态 → 就绪态:当进程的运行时间片用完或发生更高优先级的进程需要执行时,操作系统会将当前进程的状态转换为就绪态,以便后续调度执行。
- 运行态 → 阻塞态:当进程请求某个事件且必须等待时(如i/o操作),操作系统会将进程的状态转换为阻塞态,直到外部事件或资源满足为止。
- 阻塞态 → 就绪态:当进程等待的事件完成时(如i/o操作完成),操作系统会将进程的状态从阻塞态转换为就绪态,以便后续调度执行。
- 运行态 → 终止态:当进程执行完毕或由于某种原因被系统终止时,进程将进入终止态。
僵尸进程
- 僵死状态(zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
- 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
- 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入z状态
僵尸进程的危害
僵尸进程本身不占用系统资源(除了进程表中的一个槽位),但它们会积累并占用越来越多的进程表条目,特别是如果父进程频繁地创建子进程而不回收它们时。在进程数量有限制的系统中(比如某些unix系统),这可能会导致无法再创建新的进程。
简单来说,就是会造成内存泄漏。
孤儿进程
- 父进程先退出,,而子进程还在运行,这时,子进程就称之为“孤儿进程”
- 孤儿进程被1号init进程(init进程是一个特殊的系统进程,它是所有用户级进程的祖先,负责在系统启动时启动其他系统进程,并在系统关闭时终止它们)领养,最后由init进程回收。
____________________
⭐感谢你的阅读,希望本文能够对你有所帮助。如果你喜欢我的内容,记得点赞关注收藏我的博客,我会继续分享更多的内容。⭐
发表评论