)
认识冯诺依曼系统操作系统概念与定位理解 管理深入理解进程概念了解 PCB学习进程状态学会创建进程掌握僵尸进程和孤儿进程及其形成原因和危害了解进程调度Linux 进程优先级理解进程竞争性与独立性理解并行与并发理解进程切换以及 Linux2.6 kernelO (1) 调度算法架构理解环境变量熟悉常见环境变量及相关指令getenv/setenv函数理解 C 内存空间分配规律了解进程内存映像和应用程序区别认识虚拟地址空间。书接上文Linux进程全面解析从基础到高级管理(1/3)https://blog.csdn.net/syagain_zsx/article/details/161751639?spm1001.2014.3001.550Linux进程全面解析从基础到高级管理(2/3)https://blog.csdn.net/syagain_zsx/article/details/161751891?spm1001.2014.3001.55023-4 进程切换与Linux2.6内核O(1)调度算法3-4-1 进程切换CPU上下文切换进程切换本质为CPU上下文切换context switch也叫任务切换、寄存器切换是多任务操作系统调度的核心过程。上下文切换完整流程当内核需要暂停当前运行进程、调度新进程运行时会先保存当前进程的运行现场再加载新进程的运行现场具体步骤如下保存现场将当前正在运行进程的CPU寄存器全部内容保存到该进程专属的栈空间中完整留存进程的运行状态加载现场从即将调度运行的新进程栈空间中读取该进程保存的寄存器数据重新载入CPU寄存器切换运行CPU基于新的寄存器上下文开始执行新进程的代码完成一次进程切换。该机制可参考Linux内核0.11底层源码实现是多进程并发运行的底层支撑。3-4-2 核心前置概念时间片Linux属于分时操作系统系统会为每一个进程分配固定的运行时间片本质是硬件计数器。时间片是进程单次占用CPU运行的最大时长当进程时间片耗尽操作系统会强制将该进程从CPU剥离触发进程切换调度其他就绪进程运行。3-4-3 Linux2.6内核 O(1) 调度队列核心架构Linux2.6内核全新设计了O(1)调度算法核心优势为进程调度耗时为常数不随系统进程数量增多而增加开销调度效率极高。1、单CPU专属运行队列runqueue系统中每一个CPU核心都独立拥有一个专属runqueue运行队列各CPU核心独立调度自身队列内的进程多CPU环境下需额外处理不同CPU runqueue之间的进程负载均衡问题避免单CPU负载过高。2、进程优先级划分规则Linux2.6内核将进程优先级分为两大区间共140个优先级档位对应调度队列数组下标普通进程优先级100 ~ 139日常用户进程均为普通进程与nice值-20 ~ 19一一对应可手动微调实时进程优先级0 ~ 99优先级高于所有普通进程用于系统关键实时任务用户一般无需配置。3、活动队列active专门存放时间片未耗尽、处于就绪状态的进程是系统当前可直接调度运行的进程队列核心结构特性nr_active记录当前活动队列中所有就绪运行态进程的总数量queue[140]进程队列数组数组下标对应进程优先级共140个队列一个下标对应一个优先级相同优先级的进程遵循FIFO先进先出规则排队调度bitmap[5]位图优化结构总计5个32位比特位共140个有效比特位一一对应140个优先级队列用于标记对应优先级队列是否为空大幅提升查找非空最高优先级队列的效率。活动队列进程调度流程通过bitmap位图快速检索从0下标最高优先级开始匹配定位到第一个非空的优先级队列即为当前优先级最高的就绪进程队列取出该队列的队首进程交付CPU执行基于bitmap检索规避遍历全部140个队列的低效操作实现常数级查找。4、过期队列expired过期队列与活动队列数据结构完全一致同样包含140个优先级队列、bitmap位图、nr_active计数专门存放时间片耗尽的进程这类进程暂时失去CPU执行权限当活动队列中所有进程时间片全部耗尽、无就绪进程时系统会为过期队列中的进程重新计算时间片等待新一轮调度。5、active与expired指针切换机制active指针永久指向当前正在调度使用的活动队列expired指针永久指向存放超时进程的过期队列随着调度推进活动队列进程逐渐减少过期队列进程持续增多核心优化机制当活动队列清空后系统直接交换active指针与expired指针的指向原过期队列直接变为新的活动队列无需迁移进程数据极致节省调度开销。3-4-4 O(1)调度算法核心总结Linux2.6内核的调度算法依托双队列结构位图优化指针交换机制让系统查找最优调度进程的时间复杂度恒定为O(1)不会因系统进程数量增加而降低调度效率完美适配多任务高并发的Linux服务场景。3-4-5 内核核心数据结构源码Linux2.6内核runqueue运行队列与优先级数组核心结构体源码struct rq { spinlock_t lock; /* * nr_running and cpu_load should be in the same cacheline because * remote CPUs use both these fields when doing load calculation. */ unsigned long nr_running; unsigned long raw_weighted_load; #ifdef CONFIG_SMP unsigned long cpu_load[3]; #endif unsigned long long nr_switches; /* * This is part of a global counter where only the total sum * over all CPUs matters. A task can increase this counter on * one CPU and if it got migrated afterwards it may decrease * it on another CPU. Always updated under the runqueue lock: */ unsigned long nr_uninterruptible; unsigned long expired_timestamp; unsigned long long timestamp_last_tick; struct task_struct *curr, *idle; struct mm_struct *prev_mm; struct prio_array *active, *expired, arrays[2]; int best_expired_prio; atomic_t nr_iowait; #ifdef CONFIG_SMP struct sched_domain *sd; /* For active balancing */ int active_balance; int push_cpu; struct task_struct *migration_thread; struct list_head migration_queue; #endif #ifdef CONFIG_SCHEDSTATS /* latency stats */ struct sched_info rq_sched_info; /* sys_sched_yield() stats */ unsigned long yld_exp_empty; unsigned long yld_act_empty; unsigned long yld_both_empty; unsigned long yld_cnt; /* schedule() stats */ unsigned long sched_switch; unsigned long sched_cnt; unsigned long sched_goidle; /* try_to_wake_up() stats */ unsigned long ttwu_cnt; unsigned long ttwu_local; #endif struct lock_class_key rq_lock_key; }; /* * These are the runqueue data structures: */ struct prio_array { unsigned int nr_active; DECLARE_BITMAP(bitmap, MAX_PRIO1); /* include 1 bit for delimiter */ struct list_head queue[MAX_PRIO]; }4 命令行参数和环境变量4-1 基本概念环境变量environment variables是操作系统中用于配置系统运行环境的全局参数系统和程序可通过读取环境变量获取路径、用户、Shell类型等运行配置信息。核心特性与作用环境变量用于指定操作系统、应用程序的运行环境参数支撑程序正常编译、链接、运行典型场景C/C程序编译链接时无需手动指定静态库、动态库路径编译器可通过系统环境变量自动检索库文件完成链接生成可执行程序环境变量具备特殊系统用途和全局特性默认可被子进程继承。4-2 常见系统环境变量Linux系统中最常用、必考的三个核心环境变量PATH命令搜索路径系统执行指令时会按照PATH记录的路径顺序依次检索可执行程序HOME用户主工作目录对应用户登录Linux系统后的默认工作目录不同用户HOME路径不同SHELL当前终端使用的Shell程序默认值通常为/bin/bash。4-3 环境变量查看方式与实操测试1、通用查看指令通过echo $环境变量名查看指定环境变量的值语法echo $NAMENAME为环境变量名称。2、PATH环境变量测试实验实验目的理解系统指令无需带路径执行、自定义程序需要带路径的核心原因。实验步骤创建测试程序hello.c#include stdio.h int main() { printf(hello world!\n); return 0; }编译生成可执行文件hello执行对比使用./hello可正常运行直接输入hello提示命令不存在核心问题解析系统自带指令ls、pwd等的程序路径已写入PATH环境变量系统可自动检索自定义程序路径未配置在PATH中必须手动指定相对/绝对路径运行临时配置PATH环境变量将程序路径加入PATH实现无路径运行程序export PATH$PATH:当前hello程序所在绝对路径配置完成后直接输入hello即可运行程序拓展方式可将程序放入系统默认命令路径如/usr/local/bin实现永久无路径执行。3、HOME环境变量测试实验切换root用户与普通用户分别执行echo $HOME对比主目录差异执行cd ~ pwd~ 波浪号本质就是HOME环境变量的值cd ~ 会直接切换到用户主目录。4-4 环境变量相关核心命令echo打印、查看指定环境变量的值例echo $PATHexport定义/导出环境变量将本地变量提升为全局环境变量可被子进程继承env查看系统所有全局环境变量unset删除指定环境变量例unset MYENVset查看Shell本地变量全局环境变量。4-5 环境变量的内核组织方式系统为每一个运行的进程单独分配一张环境表用于存储当前进程的所有环境变量。存储结构环境表是一个字符指针数组数组中每个指针指向一条以\0结尾的环境变量字符串数组以 NULL 指针结尾标识环境表结束。4-6 代码获取环境变量的两种方式1、通过main函数第三个参数 env[]main函数完整参数int main(int argc, char *argv[], char *env[])其中 env 即为环境变量表指针数组。#include stdio.h // argc:参数个数 argv:命令行参数 env:环境变量表 int main(int argc, char *argv[], char *env[]) { int i 0; // 遍历打印所有环境变量 for(; env[i]; i){ printf(%s\n, env[i]); } return 0; }2、通过全局变量 environ 获取libc库内置全局变量environ专门指向进程环境变量表该变量无对应头文件使用时必须手动extern声明。#include stdio.h // 声明库全局变量 extern char **environ; int main(int argc, char *argv[]) { int i 0; for(; environ[i]; i){ printf(%s\n, environ[i]); } return 0; }4-7 系统调用获取指定环境变量getenv开发中无需遍历全部环境变量可通过getenv()精准获取指定环境变量putenv()用于设置环境变量后续详解。#include stdio.h #include stdlib.h // getenv头文件 int main() { // 精准获取PATH环境变量 printf(%s\n, getenv(PATH)); return 0; }4-8 环境变量全局属性可被子进程继承核心特性环境变量具备全局属性父进程的全局环境变量会自动继承给所有子进程。测试代码读取自定义环境变量#include stdio.h #include stdlib.h int main() { // 读取自定义环境变量MYENV char *env getenv(MYENV); if(env){ printf(MYENV %s\n, env); }else{ printf(MYENV 环境变量不存在\n); } return 0; }实验验证继承特性直接运行程序无输出自定义变量不存在终端导出全局环境变量export MYENVhello world再次运行程序可成功打印变量值证明终端父进程的全局环境变量可被程序子进程继承。4-9 重点实验本地变量与环境变量区别1、本地变量测试仅执行MYENVhelloworld不使用export导出该变量为Shell本地变量仅当前终端有效不会写入进程环境表子进程无法继承运行上述测试程序无法读取该变量。2、全局变量测试执行export MYENVhelloworld变量升级为全局环境变量写入环境表所有子进程均可继承读取。3、永久环境变量配置拓展临时export的环境变量终端关闭即失效可修改配置文件实现永久生效用户级配置~/.bashrc、~/.bash_profile仅当前用户生效系统级配置/etc/profile、/etc/bashrc所有用户生效修改文件后执行source 配置文件立即生效。4-10 本章核心总结环境变量是系统运行配置参数具备全局特性默认被子进程继承PATH是核心检索路径决定系统指令的查找范围本地Shell变量无法被子进程继承export导出的全局环境变量可继承代码获取环境变量三种方式env参数、environ全局变量、getenv系统调用。