进程及进程调度

简介: 1 .1 进程结构 每个进程都具有自己的属性,用一个task_struct数据结构来表示,它包含了进程的详细信息,主要有进程标识符(PID)、进程所占的内存区域、相关文件描述符、安全信息、进程环境、信号处理、资源安排、同步处理状态几个方面。

1 .1 进程结构

每个进程都具有自己的属性,用一个task_struct数据结构来表示,它包含了进程的详细信息,主要有进程标识符(PID)、进程所占的内存区域、相关文件描述符、安全信息、进程环境、信号处理、资源安排、同步处理状态几个方面。

数组task包含指向系统中所有task_struct结构的指针。创建进程时,Linux将从系统内存中分配一个task_struct结构,并将其加入task数组。操作系统初始化后,建立init进程,它建立一个task_struct数据结构INIT_TASK。当前运行进程的结构用current指针来指示。

进程切换包含三个层次:

1)用户数据的保存 包括正文段、数据段(DATA,BSS)、堆栈段(STACK)、共享内存段(SHARED MEMORY)。

2)寄存器数据的保护 包含PC、PSW(处理器状态字)、SP(栈指针)、PCBP(进程控制块指针)、FP(指向栈中一个函数的local变量的首地址)、P(指向栈中调用函数的实参位置)、ISP(中断栈指针),以及其他通用寄存器等。

3)系统级的保护 包括proc、u‘虚拟存储器空间管理表格、中断处理栈。

(PROC文件系统是Linux中的特殊文件系统,提供给用户一个可以了解内核内部工作过程的可读窗口,在运行时访问内核内部数据结构、改变内核设置的机制。)

 

状态为TASK_INTERRUPTBLE或TASK_UNINTERRUPTIBLE的睡眠进程得到它需要的资源被唤醒,通过schdule()进入TASK_RUNNING状态。状态TASK_UNINTERRUPTIBLE的睡眠进程,不能被信号或定时器中断唤醒,只有它申请的资源有效时才能被唤醒。

进程执行do_exit()后进入状态TASK_ZOMBILE,释放所申请的资源。

 1.2 进程的创建

1.2.1对象缓存的分配

在系统启动时的启动内核函数中,有进程管理的初始化函数,其中fork_init函数初始化线程数,分配进程结构的对象缓存。各个进程创建时进程结构对象从这里分配空间。

1.2.1系统调用sys_fork

当系统调用sys_fork创建一个进程的时候,它直接调用了实现函数do_fork。do_fork函数拷贝父进程的相关数据,如文件、信号量、内存等。完成进程初始化后,由父进程调用wake_up_process()函数将其唤醒,状态变为TASK_RUNNING,挂到就绪队列,返回子进程的pid。(创建完成的子进程会挂到就绪队列)

 1.3 内核线程

一个进程可以拥有多个线程。如果进程运行在SMP机器上,多个CPU执行各个线程,这样达到最大程度的并行。线程的上下文切换开销就比进程要小多了,线程共享了进程中除CPU以外的其他资源。

线程有内核线程、轻量级进程和用户线程三种,其中内核线程在内核调度,可并发使用多个处理器。用户线程在用户空间实现,它减少了上下文切换开销,它并行处理一个进程中的多个事务。

1)内核线程

内核线程是由内核创建和撤销的,用来执行一个指定的函数。内核线程共享内核的正文段内核全局数据,但各自具有自己的内核堆栈。它能够被单独调度,并且使用标准的内核同步机制,可以被单独分配到一个处理器上运行。内核线程实际上是一个与父进程共享地址空间的进程。

2)轻量级进程

轻量级进程是内核支持的用户线程。它在一个单独的进程中提供多线程控制。这些轻量级进程被单独调度,可以在多个处理器上运行,每一个轻量级进程都被绑定在一个内核线程上。轻量级进程不被独立调度,并且共享地址空间和进程中的其他资源,但是每个轻量级进程都应该有自己的程序计数器、寄存器集合、核心栈和用户栈。

3)用户线程

用户线程是通过线程库实现的。它们是在没有内核的参与下进行创建、释放和管理的。线程库提供了同步和调度的方法。用户线程的上下文在没有内核干预的情况下保存和恢复。每个用户线程可以有自己的用户堆栈,一块用来保存用户级寄存器上下文,以及入如信号屏蔽等状态信息的内存区。

内核只调度用户线程下的进程,这些进程再通过线程库函数来调度它们的线程。

 1.4 工作队列

工作队列接口是用于调度内核工作任务的。每个工作队列使用一个专门线程,所有来自运行队列的工作任务在这个线程中运行,而线程是在进程的上下文中运行的。因此可在适当时间调度此线程来运行工作任务。

 

 1.5 进程调度

在linux中,每一个CPU维护一个自己的runqueue结构的就绪队列。

1.5.1 runqueue结构

runqueue结构是主要的CPU运行队列数据结构。运行队列用来按照优先级来管理进程,每个运行队列代表一定优先级的进程的链表。与工作队列的区别是:一个工作队列运用一个线程来运行工作队列中的各种工作任务,而内核线程实质也是一种进程,工作队列与运行队列是完全不相关的两个概念。

1.5.2 进程调度初始化

linux的进程有schedule函数执行。它只在内核态运行,任何进程从系统调用返回时会转入schedule()。大多数中断服务程序在中断响应完成后,也会转入schedule().

1)调度器的初始化

函数sched_init初始化调度器

2)进程调度器相关环境的建立

函数sched_fork为进程p建立调度器相关环境,进程p是由当前进程用函数fork()新建的进程。

在进程创建fork系统调用中会调用do_fork函数,在do_fork函数中会调用到copy_process函数,而copy_process函数调用到了sched_fork函数,这说明进程创建时,就会建立调度器相关环境。shed_fork函数给进程p分配时间片,打上时间戳。

1.5.3 函数schedule分析

进程的调度有直接启动调度和被动调度两种方式,在不同的方式下调度执行的步骤是不一样的:

1)直接启动调度

直接启动调度发生在当前进程因资源而需要进入被阻塞状态时。调度程序执行的步骤如下:

a 把当前进程放到适当的等待队列里;

b 把当前进程的state设为TASK_INTERRUPTIBEL或者TASK_UNINTERRUPTIBEL;

c 调用schedule(),准备让新的进程掌握CPU

d 检查当前进程所需的资源是否可用,如果是,则把当前进程从等待队列里删除。

2)被动调度

通过在当前进程的need_resched设为1来实现被动调度,每次调入一个用户态进程之前,这个变量的值都会被检查,来决定是否调用函数schedule()来实现调度

函数schedule的功能是选择一个合适的进程在CPU上执行,它的基本流程分为五个操作步骤:

1)清理当前运行中的进程

2)选择下一个投入运行的进程

3)设置新进程的运行环境

4)执行进程上下文切换

5)后期整理

 1.6 Linux内核抢占

内核抢占就是让调度程序能尽可能多地运行,从而减少了从一个事件发生到调度程序被执行的时间延迟。在当前进程具有被“安全”抢占条件,并且有一个等待处理的重新调度请求时,内核就调用调度程序来进行进程调度。

内核抢占要求内核中所有可能为一个以上进程共享的变量和数据结构都要通过互斥机制加以保护,或者说都要放在临界区中。在抢占式内核中,认为如果内核不是在一个中断处理程序中,并且不在spinlock保护的代码中,就任务可以“安全”地进行切换。

抢占式内核实现的原理是在释放spinlock时,或者当中断返回时,如果当前执行进程的need_resched被标记,则进行抢占式调度。

 

 

 

 

 

相关文章
|
10天前
|
算法 调度 UED
深入理解操作系统:进程管理与调度策略
【8月更文挑战第28天】在数字世界的心脏,操作系统扮演着不可或缺的角色。本文将深入浅出地探讨操作系统中的核心概念——进程管理及其调度策略。从进程的诞生到结束,我们将一探究竟,揭示如何高效利用CPU资源,确保系统的流畅运行。文章还将通过实际代码示例,展示进程创建和调度的奥秘,让读者对操作系统有一个更加直观和深刻的认识。
|
11天前
|
资源调度 算法 Linux
深入理解操作系统之进程调度
【8月更文挑战第27天】本文将带你进入操作系统的核心世界,探索神秘的进程调度机制。我们将以通俗易懂的语言,深入浅出地介绍进程调度的基本概念、常见算法及其实现原理,让你对操作系统有更深入的了解。同时,我们还将通过实际代码示例,让你亲自感受进程调度的魅力。让我们一起揭开操作系统的神秘面纱,探索进程调度的奥秘吧!
|
17天前
|
算法 调度 UED
揭秘操作系统背后的暗战:进程调度与优先级反转的惊心动魄!
【8月更文挑战第21天】操作系统核心管理计算机资源,进程调度为其关键功能,决定CPU使用权,影响系统性能与用户体验。优先级反转是多任务环境下常见挑战:高优先级进程因等待低优先级进程占用的资源而被阻塞,导致系统效率下降。通过优先级继承或提升机制可解决此问题,确保系统资源高效利用与响应时间优化。
26 1
|
1月前
|
算法 调度 Python
深入理解操作系统:进程调度的奥秘
【8月更文挑战第4天】操作系统是计算机系统的核心,其中进程调度是其重要的组成部分。本文将深入探讨进程调度的原理和实现,包括进程调度的目标、常用的调度算法以及如何在实际中应用这些知识。我们将通过代码示例来展示进程调度的具体实现,帮助读者更好地理解和掌握这一关键技术。
|
9天前
|
算法 调度 UED
深入理解操作系统中的进程调度
【8月更文挑战第29天】操作系统是计算机系统的核心,负责管理硬件资源和提供各种服务。其中,进程调度是操作系统中至关重要的一环,它决定了哪些进程将获得处理器时间以及何时获得。本文将从进程调度的基本概念出发,探讨不同类型的调度算法及其优缺点,并通过实际代码示例加深理解。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供有价值的见解和知识。
20 8
|
7天前
|
算法 安全 网络安全
探索操作系统核心:进程调度的奥秘网络安全的盾牌与剑——漏洞防御与加密技术
【8月更文挑战第30天】在数字世界的每一次点击和命令背后,都隐藏着一个不为人知的英雄——进程调度器。它默默无闻地在后台工作,确保我们的命令得以流畅执行。本文将揭开这位幕后英雄的面纱,带你了解进程调度的原理、重要性以及它是如何在操作系统中发挥作用的。无论你是编程新手还是资深开发者,理解进程调度都能帮你更好地掌握计算机的运作原理。准备好深入操作系统的核心,一探究竟了吗?让我们开始吧!
|
8天前
|
算法 调度 开发者
深入理解操作系统:进程管理与调度
【8月更文挑战第30天】本文将带你进入操作系统的核心世界,探索进程管理的奥秘和进程调度的策略。我们将通过直观的例子和代码片段,揭示操作系统如何有效管理计算资源,确保系统稳定运行和高性能。你将了解进程状态的变迁、调度算法的原理以及如何在实际编程中利用这些知识。无论你是操作系统的学习者还是软件开发的实践者,这篇文章都将为你提供宝贵的洞见。
|
11天前
|
运维 算法 调度
深入理解操作系统:进程调度与优先级自动化运维:使用Ansible实现服务器集群管理
【8月更文挑战第27天】在操作系统的众多奥秘中,进程调度无疑是一个既简单又复杂的主题。它就像是交响乐团中的指挥,协调着每一个音符,确保乐曲和谐而有序地进行。本文将带领读者走进进程调度的世界,探索其背后的原理和实现,同时通过代码示例揭示其精妙之处。让我们一起揭开进程调度的神秘面纱,理解它在操作系统中的重要性。
|
17天前
|
算法 Linux 调度
深入理解操作系统中的进程调度策略
【7月更文挑战第52天】 在多任务操作系统中,进程调度是核心功能之一,其决定了处理器资源分配的公平性和效率。本文将深入探讨几种常见的进程调度策略,包括先来先服务(FCFS)、短作业优先(SJF)和轮转调度(RR),并分析各自的优势与局限。通过比较不同策略在响应时间、等待时间和系统吞吐量方面的表现,我们旨在为读者提供一个清晰的指导,以选择适合特定应用场景的最佳调度算法。
|
19天前
|
存储 Linux API
Linux源码阅读笔记08-进程调度API系统调用案例分析
Linux源码阅读笔记08-进程调度API系统调用案例分析

相关实验场景

更多
下一篇
DDNS