本地主机做网站,dw网站的滑屏怎么做,做那种事情的网站,2022年企业所得税税率表一览目录
前言
1. 进程的状态
1.1 进程排队
1.2 运行#xff0c;阻塞#xff0c;挂起
2.Linux下具体的进程状态
2.1僵尸和孤儿 3.进程的优先级 4.Linux的调度与切换 前言 这篇继续来学习进程的其它知识 上篇文章#xff1a;Linux--进程#xff08;1#xff09;-CS…目录
前言
1. 进程的状态
1.1 进程排队
1.2 运行阻塞挂起
2.Linux下具体的进程状态
2.1僵尸和孤儿 3.进程的优先级 4.Linux的调度与切换 前言 这篇继续来学习进程的其它知识 上篇文章Linux--进程1-CSDN博客 1. 进程的状态 关于进程的状态 首先我们来轻量聊一下进程排队这件事情--队列 然后谈一谈教材上关于进程状态的表述---运行阻塞挂起 最后看看Linux下具体的进程状态具体的看看什么是运行什么是阻塞什么是挂起 1.1 进程排队 进程不是一直在运行的进程放在了cpu上也不是一直在前全运行的 进程不是在一直运行的也可能在等待某中软硬件资源比如我们在写c语言代码的时候运行到scanf那一行进程就在等待输入。 进程放在了cpu上也不是一直在前全运行的每个进程都会被分配一个时间段我们称之为时间片如果时间结束该进程还在运行CPU将进行剥夺资源并分配给另一个进程。我们写代码的时候有时候会遇到死循环当代码运行生成了进程进程时间结束我们会发现循环仍未终止但实际上这个进程资源已经被剥夺了。在Linux系统上他可能在5毫秒到800毫秒之间。由于时间片极短用户不会感觉到程序的切换从而形成了多个进程同时运行的错觉。 我们接着来谈谈排队的问题 首先进程排队一定是在等待某种资源 1.进程task_struct可执行程序进程排队不是可执行程序在排队而是task_struct对象PCB在排队比如你实习投简历的时候是简历在排队不是你人在排队。 2.PCB的问题 一个进程的PCB可以被链入多种数据结构中在不同的场景下操作系统可能会采用不同的数据结构来组织和管理PCB。一个PCB通常不会同时被链接到多种数据结构中。它会被放置在最适合当前管理需求的数据结构中。例如当进程处于 就绪状态时它的PCB会被放在就绪队列中当进程因等待某个事件而被阻塞时它的PCB会被移到阻塞队列中。操作系统会根据需要动态地更新和移动PCB以确保进程能够按照正确的顺序和方式得到调度和执行。 1.2 运行阻塞挂起 1.所谓的状态本质就是在task_struct中的一个整型变量 eg所谓的状态不过是status所被给予的数字 2.状态决定了什么 状态决定了进程的后续动作Linux中可能存在多个进程都要根据他的状态执行后续的动作。在这种情况下就需要让进程去排队了一个CPU一个运行队列 运行状态运行状态是进程实际占用CPU执行其程序代码的状态。我们在主流的操作系统中只要进程处在运行队列中排队我们都可以称这个进程在运行状态。 在前面我们说了进程不是在一直运行的也可能在等待某中软硬件资源进程放在了cpu上也不是一直在前全运行的。 在这里我以硬件为例来了解阻塞状态。 操作系统管理硬件要先把硬件表述起来再去管理每个硬件都有属于自己的对象cup也是硬件他有他的运行队列其它硬件也有其它硬件的队列称之为等待队列。 我引用上面的例子当代码运行到scanf的时候进程就在等待输入这时进程的状态就会从运行状态变为阻塞状态进程会被操作系统OS搬迁到键盘的等待队列中去当输入完成之后OS就会知道进程已经就绪了这时进程又会重新被搬迁到运行队列中去此时进程变为运行状态。状态的变迁实际上就是OS将PCB搬迁到不同的队列中 总结阻塞状态当我们的进程正在等待软硬件资源的时候资源如果没有就绪我们的进程task_struct只能1.将自己设置为阻塞状态 2.将自己的PCB链入等待的资源提供的等待队列中去。 挂起状态这个状态并不常见这个状态的前提是计算机资源已经比较吃紧了。因为这些进程暂时没有动作此时OS就会将阻塞状态的进程代码和数据不包括PCB转到外设中存磁盘的swap分区储起来唤出需要时再唤入。 2.Linux下具体的进程状态 为了弄明白正在运行的进程是什么意思我们需要知道进程的不同状态。一个进程可以有几个状态在Linux内核里进程有时候也叫做任务。 下面的状态在kernel源代码里定义 /*
* 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。 我们举一个样例来看看在Linux中状态具体的样子。 我们运行这个代码查看了这个进程的状态发现它处于S阻塞状态这时我们就有疑问了这段代码进入了死循环应该是一直在运行的啊不应该是R运行状态吗 这是因为printf的缘故这个程序的大多数时间都在执行printf函数这时就会发生系统调用访问外设在这些系统调用期间进程大多数时间都是处于等待的状态。所以就会处于S状态。 此时我们把printf删去这个程序就只做死循环了不会去访问任何外设这时候进程就一直处于运行状态了。 进程后面的含义表示这个进程是前台进程。如果我们在运行可执行程序的时候后面加上符合这时就会变成后台进程没有进行标识了。此时进程进行CTRLC是无法终止的只能使用kill指令杀掉该进程。 D磁盘休眠状态Disk sleep有时候也叫不可中断睡眠状态uninterruptible sleep在这个状态的进程通常会等待IO的结束。在资源极度紧张的情况操作系统主动杀掉了进程为了避免这种情况就引入了这个状态等磁盘工作完返回给进程进程任务完成了才结束。这个状态也属于阻塞状态因为它在等待资源就绪。T停止状态stopped 可以通过发送 SIGSTOP 信号给进程来停止T进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。t停止状态这个状态一般在调试代码对代码进行打断点的操作时等待你的的下一步操作此时进程就会处于t状态。T/t也可以理解成一种阻塞状态因为在这个状态进程也是在等待某种资源的就绪 kill命令的第19号选项就可以让进程暂停在输入18号选项就可以就绪了。但被继续的进程会自动转为后台进程。下面是示例 X死亡状态dead这个状态只是一个返回状态你不会在任务列表里看到这个状态 2.1僵尸和孤儿 Z僵尸状态(zombie) 1.僵死状态Zombies是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程 2.僵死进程会以终止状态保持在进程表中并且会一直在等待父进程读取退出状态代码。 3.所以只要子进程退出父进程还在运行但父进程没有读取子进程状态子进程进入Z状态 来一个创建僵死进程例子 #include stdio.h
#includestdlib.h
#include unistd.h
int main()
{pid_t id fork();if (id 0){//childint cnt 5;while (cnt){printf(I am child,pid:%d,ppid:%d\n, getpid(), getppid());sleep(1);cnt--;}exit(0);//让子进程退出 }//fatherwhile (1){printf(I am father,pid:%d,ppid:%d\n, getpid(), getppid());sleep(1);}return 0;
} 编译并在另一个终端下启动监控 开始测试 看到结果 我们看到子进程已经进入僵尸状态了此时子进程已经死了只是还要维持到被父进程读取 为什么要有Z状态 创建进程是希望这个进程给用户完成工作的子进程必须有结果数据PCB中的。 僵尸进程危害 进程的退出状态必须被维持下去因为他要告诉关心它的进程父进程你交给我的任务我办的怎么样了。可父进程如果一直不读取那子进程就一直处于Z状态是的维护退出状态本身就是要用数据维护也属于进程基本信息所以保存在task_struct(PCB)中换句话说 Z状态一直不退出 PCB一直都要维护是的那一个父进程创建了很多子进程就是不回收是不是就会造成内存资源的浪费是的因为数据结构对象本身就要占用内存想想C中定义一个结构体变量对象是要在内存的某个位置进行开辟空间内存泄漏如何解决呢在这里我们见一个函数wait后面我们在详细的介绍 开始5s子进程和父进程一起进行5s后子进程进入僵尸状态父进程10s父进程结束执行wait函数回收子进程资源获取子进程状态bash创建的子进程bash会自动回收 孤儿进程 父进程如果提前退出那么子进程后退出进入Z之后那该如何处理呢父进程先退出子进程就称之为“孤儿进程” 我们重新设置一下代码让父进程先结束 测试结果 我们发现父进程结束后子进程转为了后台进程且父进程为”1“1号进程其实就是操作系统也就是说父进程结束后它的子进程将会被操作系统领养。 3.进程的优先级 是什么 前提进程需要访问某种资源进程通过一定的方式排队确认享受资源的先后顺序 为什么 因为资源有限。 怎么办 在Linux中你可以使用多种方法来查看和修改进程的优先级。 在linux或者unix系统中用ps –l命令则会类似输出以下几个内容 我们很容易注意到其中的几个重要信息有下 UID : 代表执行者的身份PID : 代表这个进程的代号PPID 代表这个进程是由哪个进程发展衍生而来的亦即父进程的代号PRI 代表这个进程可被执行的优先级其值越小越早被执行NI 代表这个进程的nice值 PRI and NI PRI也还是比较好理解的即进程的优先级Linux的默认优先级是80或者通俗点说就是程序被CPU执行的先后顺序此值越小进程的优先级别越高Linux优先级的范围是[60,99]---40。那NI呢?就是我们所要说的nice值了其表示进程可被执行的优先级的修正数值PRI值越小越快被执行那么加入nice值后将会使得PRI变为 PRI(new)PRI(old)nice这样当nice值为负值的时候那么该程序将会优先级值将变小即其优先级会变高则其越快被执行。所以调整进程优先级在Linux下就是调整进程nice值。nice其取值范围是-20至19一共40个级别。 PRI vs NI 需要强调一点的是进程的nice值不是进程的优先级他们不是一个概念但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据 用top命令更改已存在进程的nice进入top后按“r”–输入进程PID–输入nice值 eg 初始状态 我给nice的值为10 此时PRI的值就为90了 Linux调整优先级为什么是要受限制的 如果不加限制将自己进程的优先级调整的非常高别人的优先级调整的非常低。优先级高的进程优先得到资源--后续还有源源不断的进程产生导致常规进程很难享受到CPU的资源这就产生了进程饥饿问题。 4.Linux的调度与切换 概念准备进程在运行的时候放在CPU上直接必须把进程代码跑完才行吗 不对现代操作系统都是基于时间片进行轮转执行的。 竞争性: 系统进程数目众多而CPU资源只有少量甚至1个所以进程之间是具有竞争属性的。为了高效完成任务更合理竞争相关资源便具有了优先级独立性: 多进程运行需要独享各种资源多进程运行期间互不干扰并行: 多个进程在多个CPU下分别同时进行运行这称之为并行并发: 多个进程在一个CPU下采用进程切换的方式在一段时间之内让多个进程都得以推进称之为并发 对于进程切换的理解 进程切换就像我们在日常生活中更换任务或活动一样是操作系统中非常关键的一个环节。当我们从一个进程切换到另一个进程时操作系统需要确保前一个进程的状态被保存下来同时加载并恢复新进程的状态。 具体来说进程切换涉及几个关键步骤。首先系统会暂停当前正在运行的进程保存其上下文信息这包括CPU寄存器的内容、内存管理信息以及程序计数器等。这些信息对于进程的恢复和继续执行至关重要。进程在执行的时候它的数据是保存在CPU的寄存器中的。 接下来系统会选择一个新的进程来运行。这个选择过程可能基于多种因素如进程的优先级、系统的调度策略等。一旦选择了新的进程系统就会恢复其上下文信息进程在运行的过程中要产生大量的临时数据放在cpu的寄存器中cpu内部所有的临时数据我们叫做进程的硬件上下文将其状态设置为就绪状态并将其加载到CPU中。 完成这些步骤后新的进程就可以开始执行了。而原来的进程则处于暂停状态等待下一次被调度执行。 进程切换的开销是相对较大的因为涉及保存和恢复上下文信息、更新系统数据结构等操作。因此操作系统会尽量优化进程切换的过程减少不必要的开销以提高系统的整体性能。执行 保存 恢复 再执行 注意cpu内的寄存器只有一套寄存器内部保存的数据可以有多套虽然寄存器数据放在了一个共享的cpu设备里面但所有的数据其实都是被进程私有的 cup内所有的数据在任意一个时刻只属于一个进程怎么理解 在任意一个时刻CPU内的数据都属于当前正在执行的进程。这是操作系统通过进程调度和CPU管理实现的确保了每个进程都能独占地使用CPU资源并且其数据不会与其他进程的数据混淆或冲突。 需要注意的是虽然CPU内的数据在任意时刻只属于一个进程但在多核CPU系统中每个核心可以同时执行不同的进程。这种情况下每个核心的数据仍然只属于它当前执行的进程但不同的核心可以同时处理不同进程的数据。寄存器寄存器的内容 对于调度的理解 这是一个cpu的运行队列Linux实现进程调度的算法考虑优先级考虑饥饿考虑效率 蓝色区域表示活跃队列时间片还没有结束的所有进程都按照优先级放在该队列 queue[140]它是task_struc*类型task_struct* queue[140] 是一个包含140个元素的数组每个元素都是一个指向 task_struct 的指针每个指针指向一个进程。它分为0-99和100-139连个部分。 如果系统使用优先级调度那么0-99这部分的队列可能用于存储优先级较高的进程为了保证用户的公平性这个区段的进程优先级都差不多。 100-139这部分包含数组的剩余40个元素。这些元素可能用于存储另一种类型的进程或任务优先级较低的进程处于不同状态的进程这些进程可能处于阻塞状态等待某些资源或事件。后台任务这些可能是系统后台运行的任务不需要立即执行 为什么这里的范围刚好是40因为进程的优先级刚好有40个等级cup调用优先级只需要根据优先级依次去调用就好了。 bitmap[5]:bitmap常用于快速检查一个元素是否存在于某个集合中或者用于高效地表示和管理大量的二进制数据。具体到bitmap[5],他是int类型的那么他就有160个bit位可以管理160个位置的信息。 如果bitmap[5]的某个位被设置为1这可意味着该位置的资源已经被占用如果设置为0则表示该资源是空闲的。队列调度算法在决定下一个要执行的任务时可能会查看这个bitmap来确定哪些资源是可用的从而选择能够利用这些资源的任务。 bitmap[5]本身并不执行调度算法它只是调度算法在决策过程中可能参考的一个数据点。实际的调度逻辑会更为复杂可能涉及多个因素如任务的优先级、资源的需求和可用性、系统的当前状态等。 红色区域表示过期队列这个结构和蓝色区域的一样他也是一个优先级数组 过期队列和活跃列结构一模一样。 过期队列上放置的进程都是时间片耗尽的进程。 当活动队列上的进程都被处理完毕之后对过期队列的进程进行时间片重新计算。 下面是对上面结构的理解有一个q的结构体我们封装成结构体数组array[0]表示蓝色区域array[1]表示红色区域。当活跃队列的进程只需完毕后交换两个结构体指针的指向就好了让过期队列的进程得以执行这样就以O(1)的时间复杂度实现了对进程的调度