技术笔记:LINUX2.6.32下的进程分析

简介: 技术笔记:LINUX2.6.32下的进程分析

前言:


什么是进程?


   进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体


  狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。


  广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。


Linux下的进程分析:


——1.组织进程——


  Linux中一般使用fork()函数创建进程;


  fork函数


//代码效果参考: http://www.lyjsj.net.cn/wx/art_23384.html

1 #include


2 pid_t fork(void);


  功能:子进程复制父进程。


  特点:调用一次,返回两次。


  一个fork例子:


1 #include


2 #include


3 #include


4 #include


5


6 int main(void)


7 {


8 pid_t pid;//进程id


9 char message;


10 int n;


11 pid = fork();


12 if (pid < 0) { //创建进程失败


13 perror("fork failed");


14 exit(1);


15 }


16 if (pid == 0) { //子进程


17 message = "This is the child\n";


18 n = 6;


19 } else { //父进程


20 message = "This is the parent\n";


21 n = 3;


22 }


23


24 for(; n > 0; n--) {


25 printf(message);


26 sleep(1);


27 }


28 return 0;


29 }


一些与进程相关的函数:


  getpid/getppid


1 #include


2 #include


3


4 pid_t getpid(void); //返回调用进程的PID号


5 pid_t getppid(void); //返回调用进程父进程的PID号


  getuid/geteuid


1 #include


2 #include


3


4 uid_t getuid(void); //返回实际用户ID


5 uid_t geteuid(void); //返回有效用户ID


  getgid/getegid


1 #include


2 #include


3


4 gid_t getgid(void); //返回实际用户组ID


5 gid_t getegid(void); //返回有效用户组ID


  进程的终止


    主要涉及的函数有 _exit() , exit() , atexit() , on_exit()。


    1. 进程的终止分为正常和异常两种。异常终止可能是由于某些信号引起的,其中的一些信号还会导致进程产生一个核心转储文件。


    2. 正常终止可以通过系统调用 _exit() 或者GNU C标准库函数exit() 实现。二者都有一个status参数,用以表示函数退出值。常用的return 函数的效果类似与 exit() 函数(这里是指在带参数的情况下,return不带参数的时候返回值则取决于C语言的版本标准以及所使用的编译器)。


    3. 不管进程正常还是异常终止,内核都会执行多个清理步骤。与系统调用 _exit() 不同的是,调用库函数 exit() 正常终止一个进程时,将会引发执行通过GNU C库函数atexit() 或 on_exit() 注册的退出处理程序(这些退出处理程序在调用函数 _exit() 或者因信号终止的情况下是不会执行的。),然后刷新stdio缓冲区。


——2进程状态转换——


   进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。


  一个进程从创建而产生至撤销而消亡的整个生命期间,有时占有处理器执行,有时虽可运行但分不到处理器、有时虽有空闲处理器但因等待某个事件的发生而无法执行,这一切都说明进程和程序不相同,它是活动的且有状态变化的,这可以用一组状态加以刻画。


     进程状态转换图:


(1)(运行态):进程是可执行的;或者正在执行,或者在运行队列中等待执行。


(2)(可中断睡眠态):进程被阻塞,等待某些条件的完成。一旦完成这些条件,内核就会将该进程的状态设置为运行态。


(3)(不可中断睡眠态):进程被阻塞,等待某些条件的完成。与可中断睡眠态不同的是,该状态进程不可被信号唤醒。


(4)(僵死态):该进程已经结束,但是其父进程还没有将其回收。


(5)(终止态):进程停止执行。通常进程在收到SIGSTOP、SIGTTIN、SIGTTOU等信号的时候会进入该状态。


状态切换的条件:


  就绪---->执行 调度


  执行----->就绪 时间片到


  执行------>等待 等待某个事件发生而睡眠


  等待------->就绪 因等待事情发生而唤醒


——进程调度——


    进程调度的一些方法:


1. 先来先去服务:


概//代码效果参考:http://www.lyjsj.net.cn/wx/art_23382.html

念:

如果早就绪的进程排在就绪队列的前面,迟就绪的进程排在就绪队列的后面,那么先来先服务(FCFS: first come first service)总是把当前处于就绪队列之首的那个进程调度到运行状态。也就说,它只考虑进程进入就绪队列的先后,而不考虑它的下一个CPU周期的长短及其他因素。


要领:


按照进程进入就绪队列的先后顺序调度并分配处理机执行。先来先服务调度算法是一种非抢占式的算法,先进入就绪队列的进程,先分配处理机运行。一旦一个进程占有了处理机,它就一直运行下去,直到该进程完成工作或者因为等待某事件发生而不能继续运行时才释放处理机。


(1)系统只要有按FIFO规则建立的后备作业队列或就绪进程队列即可,就是一个作业控制块JCB或进程控制块PCB加入队列时加在相应队列末尾。


(2)调度退出队列时从相应队列首开始顺序扫描,将相关的JCB或PCB调度移出相应队列。


优点:有利于长作业以及CPU繁忙的作业


缺点:不利于短作业以及I/O繁忙的作业


2. 短作业(进程)优先调度算法SJ(P)F


概念:对预计执行时间短的作业(进程)优先分派处理机.通常后来的短作业不抢先正在执行的作业.


优点:


比FCFS改善平均周转时间和平均带权周转时间,缩短作业的等待时间;


提高系统的吞吐量;


缺点:


对长作业非常不利,可能长时间得不到执行;


未能依据作业的紧迫程度来划分执行的优先级;


难以准确估计作业(进程)的执行时间,从而影响调度性能。


3. 轮转法


概念:让每个进程在就绪队列中的等待时间与享受服务的时间成正比例。


定义:


时间片轮转法类似于“轮流坐庄”的思想,条件是:各作业近似认为“同时”到达,题中条件是后面作业依次比前一个作业迟到一个时间单位,分析时要严格按照RR调度算法的实现思想:系统把所有就绪进程按先入先出的原则排成一个队列。新来的进程加到就绪队列末尾。每当执行进程调度时,进程调度程序总是选出就绪队列的对首进程,让它在CPU上运行一个时间片的时间。当进程用完分给它的时间片后,调度程序便停止该进程的运行,并把它放入就绪队列的末尾。


4. 多级反馈队列算法


概念:


设置多个就绪队列,分别赋予不同的优先级,如逐级降低,队列1的优先级最高。每个队列执行时间片的长度也不同,规定优先级越低则时间片越长,如逐级加倍。


新进程进入内存后,先投入队列1的末尾,按FCFS算法调度;若按队列1一个时间片未能执行完,则降低投入到队列2的末尾,同样按FCFS算法调度;如此下去,降低到最后的队列,则按“时间片轮转”算法调度直到完成。


仅当较高优先级的队列为空,才调度较低优先级的队列中的进程执行。如果进程执行时有新进程进入较高优先级的队列,则抢先执行新进程,并把被抢先的进程投入原队列的末尾。


多级反馈队列调度算法又称反馈循环队列或多队列策略,主要思想是将就绪进程分为两级或多级,系统相应建立两个或多个就绪进程队列,较高优先级的队列一般分配给较短的时间片。处理器调度先从高级就绪进程队列中选取可占有处理器的进程,只有在选不到时,才从较低级的就绪进程队列中选取。


优点:


为提高系统吞吐量和缩短平均周转时间而照顾短进程。


为获得较好的I/O设备利用率和缩短响应时间而照顾I/O型进程。


不必估计进程的执行时间,动态调节


1.LINUX下影响进程调度的因素


  Linux的调度是基于分时技术的,给每个可运行进程分配一个时间片,当进程运行结束或时间片到期时,进程就发生切换。在Linux调度算法中,每次进程切换,内核扫描可运行进程链表,计算进程的优先级,有时会用复杂的算法求出进程的当前优先级,选择“最适合”的进程运行(在未说明SMP时,默认为单处理器系统),即每个进程都有一个值与之相关联,这个值用来表示进程如何适当地分配给CPU,也就是进程的优先级。


  例子:LINUX进程调度之CFS算法


  2.1进程权重


在完全公平调度算法中,最重要的是根据优先级确定的权重,以及由权重不同产生的CPU时间。


不同优先级的权重如下:


static constint prio_to_weight【40】 = {


/ -20 / 88761, 71755, 56483, 46273, 36291,


/ -15 / 29154, 23254, 18705, 14949, 11916,


/ -10 / 9548, 7620, 6100, 4904, 3906,


/ -5/ 3121, 2501, 1991, 1586, 1277,


/ 0/ 1024, 820, 655, 526, 423,


/ 5/ 335, 272, 215, 172, 137,


/ 10/ 110, 87, 70, 56, 45,


/ 15/ 36, 29, 23, 18, 15,


};


对应优先级从100-139(也可以说是从nice值-20-19),其权重基准是0对应1024,从0提高到1,权重减少10%,从0到-1,即优先级提高一个等级,权重增加10%的CPU时间。


就绪进程有个权重的总和,当有进程启动或者加入到队列里,系统就会根据每个进程的权重算出总的权重,留待后面使用;反之,当有进程没有就绪则将其权重从总和中减掉,可参考函数inc_nr_running()和dec_nr_running()


  2.2时钟统计


1 static void __sched_fork(struct task_structp)


2


3 {


4


5 p->se.exec_start = 0; //进程开始运行时间


6


7 p->se.sum_exec_runtime = 0;//本次总的运行时间


8


9 p->se.prev_sum_exec_runtime = 0;//上次总的运行时间,该值在调度到另外一个进程时由当前的运行时间赋值,即se->prev_sum_exec_runtime = se->sum_exec_runtime;


10


11 }


12


13 在时钟中断函数中会周期执行task_tick_fair()函数,里面统计一些时间变量。


14


15 static voidupdate_curr(struct cfs_rq cfs_rq)


16


17 {


18


19 struct sched_entity curr =cfs_rq->curr;


20


21 u64 now = rq_of(cfs_rq)->clock; //取得当前时间


22


23 unsigned long delta_exec;


24


25 ……


26


27 delta_exec = (unsigned long)(now -curr->exec_start); //进程执行的时间


28


29 update_curr(cfs_rq, curr, delta_exec);


30


31 curr->exec_start = now; //更新进程开始的运行时间


32


33 …..


34


35 }


36


37


38


39 static inlinevoid


40


41 update_curr(structcfs_rq cfs_rq, struct sched_entity curr,


42


43 unsigned long delta_exec)


44


45 {


46


47 ……


48


49 curr->sum_exec_runtime += delta_exec;


50


51 ……


52


53 delta_exec_weighted = delta_exec;//从时钟计算中得出的运行时间


54


55 if (unlikely(curr->load.weight !=NICE_0_LOAD)) {


56


57 delta_exec_weighted =calc_delta_fair(delta_exec_weighted,


58


59 &curr->load);//考虑了权重以后的运行时间


60


61 }


62


63 curr->vruntime += delta_exec_weighted; //该值判断进程在红黑树中的位置,该值越小,越靠近左边,越容易被重新调度到,反之,越到,越是右移,调度机会变小


64


65 }


66


67


68


69 在时钟周期中统计完时间后,就要判断该进程运行时间是否已经到达分配给它的份额:


70


71 static void


72


73 check_preempt_tick(structcfs_rq cfs_rq, struct sched_entity curr)


74


75 {


76


77 unsigned long ideal_runtime, delta_exec;


78


79


80


81 ideal_runtime = sched_slice(cfs_rq,curr);//计算当前进程允许占用的时间。


82


83 delta_exec = curr->sum_exec_runtime -curr->prev_sum_exec_runtime;


84


85 if (delta_exec > ideal_runtime)


86


87 resched_task(rq_of(cfs_rq)->curr);//设立调度标记


88


89 }


——自己对该操作系统进程模型的看法——


  由于先前接触的操作系统就是windows,对LINUX了解不多,但是开源的LINUX方便初学者更好的深入学习操作系统,也许对LINUX具体模型搭建还不了解,但是对进程的核心有了更多了解


2018-05-01

相关文章
|
14天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
44 4
linux进程管理万字详解!!!
|
5天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
41 8
|
9天前
|
运维 JavaScript jenkins
鸿蒙5.0版开发:分析CppCrash(进程崩溃)
在HarmonyOS 5.0中,CppCrash指C/C++运行时崩溃,常见原因包括空指针、数组越界等。系统提供基于posix信号机制的异常检测能力,生成详细日志辅助定位。本文详解CppCrash分析方法,涵盖异常检测、问题定位思路及案例分析。
29 4
|
9天前
|
运维 监控 JavaScript
鸿蒙next版开发:分析JS Crash(进程崩溃)
在HarmonyOS 5.0中,JS Crash指未处理的JavaScript异常导致应用意外退出。本文详细介绍如何分析JS Crash,包括异常捕获、日志分析和典型案例,帮助开发者定位问题、修复错误,提升应用稳定性。通过DevEco Studio收集日志,结合HiChecker工具,有效解决JS Crash问题。
27 4
|
13天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
47 4
|
14天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
16天前
|
消息中间件 存储 Linux
|
22天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
24 1
|
4天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
22 3