Linux读书笔记第三、四章
第三章
主要内容:
- 进程和线程
- 进程的生命周期
- 进程的创建
- 进程的终止
1. 进程和线程
进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作(比如,创建,销毁等)都是有内核来实现的。
Linux中的进程于Windows相比是很轻量级的,而且不严格区分进程和线程,线程不过是一种特殊的进程。
所以下面只讨论进程,只有当线程与进程存在不一样的地方时才提一下线程。
进程提供2种虚拟机制:虚拟处理器和虚拟内存
每个进程有独立的虚拟处理器和虚拟内存,
每个线程有独立的虚拟处理器,同一个进程内的线程有可能会共享虚拟内存。
内核中进程的信息主要保存在task_struct中(include/linux/sched.h)
进程标识PID和线程标识TID对于同一个进程或线程来说都是相等的。
Linux中可以用ps命令查看所有进程的信息:
ps -eo pid,tid,ppid,comm
2. 进程的生命周期
进程的各个状态之间的转化构成了进程的整个生命周期。
3. 进程的创建
Linux中创建进程与其他系统有个主要区别,Linux中创建进程分2步:fork()和exec()。
fork: 通过拷贝当前进程创建一个子进程
exec: 读取可执行文件,将其载入到内存中运行
创建的流程:
- 调用dup_task_struct()为新进程分配内核栈,task_struct等,其中的内容与父进程相同。
- check新进程(进程数目是否超出上限等)
- 清理新进程的信息(比如PID置0等),使之与父进程区别开。
- 新进程状态置为 TASK_UNINTERRUPTIBLE
- 更新task_struct的flags成员。
- 调用alloc_pid()为新进程分配一个有效的PID
- 根据clone()的参数标志,拷贝或共享相应的信息
- 做一些扫尾工作并返回新进程指针
创建进程的fork()函数实际上最终是调用clone()函数。
创建线程和进程的步骤一样,只是最终传给clone()函数的参数不同。
比如,通过一个普通的fork来创建进程,相当于:clone(SIGCHLD, 0)
创建一个和父进程共享地址空间,文件系统资源,文件描述符和信号处理程序的进程,即一个线程:clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)
在内核中创建的内核线程与普通的进程之间还有个主要区别在于:内核线程没有独立的地址空间,它们只能在内核空间运行。
这与之前提到的Linux内核是个单内核有关。
4. 进程的终止
和创建进程一样,终结一个进程同样有很多步骤:
子进程上的操作(do_exit)
- 设置task_struct中的标识成员设置为PF_EXITING
- 调用del_timer_sync()删除内核定时器, 确保没有定时器在排队和运行
- 调用exit_mm()释放进程占用的mm_struct
- 调用sem__exit(),使进程离开等待IPC信号的队列
- 调用exit_files()和exit_fs(),释放进程占用的文件描述符和文件系统资源
- 把task_struct的exit_code设置为进程的返回值
- 调用exit_notify()向父进程发送信号,并把自己的状态设为EXIT_ZOMBIE
- 切换到新进程继续执行
子进程进入EXIT_ZOMBIE之后,虽然永远不会被调度,关联的资源也释放掉了,但是它本身占用的内存还没有释放,
比如创建时分配的内核栈,task_struct结构等。这些由父进程来释放。
父进程上的操作(release_task)
父进程受到子进程发送的exit_notify()信号后,将该子进程的进程描述符和所有进程独享的资源全部删除。
从上面的步骤可以看出,必须要确保每个子进程都有父进程,如果父进程在子进程结束之前就已经结束了会怎么样呢?
子进程在调用exit_notify()时已经考虑到了这点。
如果子进程的父进程已经退出了,那么子进程在退出时,exit_notify()函数会先调用forget_original_parent(),然后再调用find_new_reaper()来寻找新的父进程。
find_new_reaper()函数先在当前线程组中找一个线程作为父亲,如果找不到,就让init做父进程。(init进程是在linux启动时就一直存在的)
第四章
主要内容:
- 什么是调度
- 调度实现原理
- Linux上调度实现的方法
- 调度相关的系统调用
1. 什么是调度
现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计算机上同时运行的各个任务(也就是进程)。
这个管理程序就是调度程序,它的功能说起来很简单:
- 决定哪些进程运行,哪些进程等待
- 决定每个进程运行多长时间
此外,为了获得更好的用户体验,运行中的进程还可以立即被其他更紧急的进程打断。
总之,调度是一个平衡的过程。一方面,它要保证各个运行的进程能够最大限度的使用CPU(即尽量少的切换进程,进程切换过多,CPU的时间会浪费在切换上);另一方面,保证各个进程能公平的使用CPU(即防止一个进程长时间独占CPU的情况)。
2. 调度实现原理
前面说过,调度功能就是决定哪个进程运行以及进程运行多长时间。
决定哪个进程运行以及运行多长时间都和进程的优先级有关。为了确定一个进程到底能持续运行多长时间,调度中还引入了时间片的概念。
2.1 关于进程的优先级
进程的优先级有2种度量方法,一种是nice值,一种是实时优先级。
nice值的范围是-20~+19,值越大优先级越低,也就是说nice值为-20的进程优先级最大。
实时优先级的范围是0~99,与nice值的定义相反,实时优先级是值越大优先级越高。
实时进程都是一些对响应时间要求比较高的进程,因此系统中有实时优先级高的进程处于运行队列的话,它们会抢占一般的进程的运行时间。
3. Linux上调度实现的方法
Linux上的调度算法是不断发展的,在2.6.23内核以后,采用了“完全公平调度算法”,简称CFS。
CFS算法在分配每个进程的CPU时间时,不是分配给它们一个绝对的CPU时间,而是根据进程的优先级分配给它们一个占用CPU时间的百分比。
比如ProcessA(NI=1),ProcessB(NI=3),ProcessC(NI=6),在CFS算法中,分别占用CPU的百分比为:ProcessA(10%),ProcessB(30%),ProcessC(60%)
因为总共是100%,ProcessB的优先级是ProcessA的3倍,ProcessC的优先级是ProcessA的6倍。
4. 调度相关的系统调用
调度相关的系统调用主要有2类:
1) 与调度策略和进程优先级相关 (就是上面的提到的各种参数,优先级,时间片等等) - 下表中的前8个
2) 与处理器相关 - 下表中的最后3个
系统调用 |
描述 |
nice() |
设置进程的nice值 |
sched_setscheduler() |
设置进程的调度策略,即设置进程采取何种调度算法 |
sched_getscheduler() |
获取进程的调度算法 |
sched_setparam() |
设置进程的实时优先级 |
sched_getparam() |
获取进程的实时优先级 |
sched_get_priority_max() |
获取实时优先级的最大值,由于用户权限的问题,非root用户并不能设置实时优先级为99 |
sched_get_priority_min() |
获取实时优先级的最小值,理由与上面类似 |
sched_rr_get_interval() |
获取进程的时间片 |
sched_setaffinity() |
设置进程的处理亲和力,其实就是保存在task_struct中的cpu_allowed这个掩码标志。该掩码的每一位对应一个系统中可用的处理器,默认所有位都被设置,即该进程可以再系统中所有处理器上执行。 用户可以通过此函数设置不同的掩码,使得进程只能在系统中某一个或某几个处理器上运行。 |
sched_getaffinity() |
获取进程的处理亲和力 |
sched_yield() |
暂时让出处理器 |
Linux读书笔记第三、四章的更多相关文章
- Linux内核分析 读书笔记 (第四章)
第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间.进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统.只有通过调度程序的合理调度,系统资源才能最大限 ...
- 05 技术内幕 T-SQL 查询读书笔记(第四章)
第四章 子查询:在外部查询内嵌套的内部查询(按照期望值的数量分为,标量子查询 scalar subqueries,多值子查询multivalued subqueries)(按照子查询对外部查询的依赖性 ...
- 20135239 益西拉姆 linux内核分析 读书笔记之第四章
chapter 4 进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统可以划分为两类: - 非抢占式多任务: - 进程会一直执行直到自己主动停止运行(这一 ...
- linux读书笔记第三章
第3章 进程管理20 3.1 进程20 进程就是处于执行期的程序(目标码存放在某种存储介质上),但进程并不仅仅局限于一段可执行程序代码.通常进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据 ...
- 《linux程序设计》--读书笔记--第十四章信号量、共享内存和消息队列
信号量:用于管理对资源的访问: 共享内存:用于在程序之间高效的共享数据: 消息队列:在程序之间传递数据的一种简单方法: 一.信号量 临界代码:需要确保只有一个进程或者一个执行线程可以进入这个临界代码并 ...
- Linux读书笔记第一、二章
第一章 Linux内核简介 1.1Unix历史 Unix特点:1.很简洁 2.所有东西都被当成文件对待 3.Unix内核和相关的系统工具软件都是用C语言编写而成 4.进程创建非常迅速 1.2追寻 ...
- C primer plus 读书笔记第十四章
这一章主要介绍C语言的结构和其他数据形式,是学习算法和数据结构的重点. 1.示例代码 /*book.c -- 仅包含一本书的图书目录*/ #include <stdio.h> #defin ...
- 初读"Thinking in Java"读书笔记之第四章 ---控制执行流程
true和false Java不允许将数字作为布尔值使用. 所有条件表达式都将布尔值作为判断条件,决定执行路径. if-lese 迭代 while,do-while,for为三个迭代语句. ,逗号操作 ...
- jQuery 实战读书笔记之第四章:使用特性、属性和数据
使用属性 /* 每个元素都有一或多个特性,,这些特性的用途是给出相应元素或其内容的附加信息.(出自 JavaScript 高级程序设计) */ /* 特性是固有的 JavaScript 对象 属性指的 ...
随机推荐
- 团队作业——Beta冲刺4
团队作业--Beta冲刺 冲刺任务安排 杨光海天 今日任务:在同队成员帮助下,完成了浏览详情界面的跳转,以及图片的嵌入 明日任务:继续完成浏览详情界面 吴松青 今日任务:研究图片详情界面后端函数,遇到 ...
- FIO_工具_专业
一.FIO工具安装: 1.查看fio是否安装 [root@localhost /]#rpm –qa|grep fio 2.源码安装(推荐) 官网地址:http://freecode.com/proje ...
- 浅析Java虚拟机结构与机制[转]
本文旨在给所有希望了解JVM(Java Virtual Machine)的同学一个概念性的入门,主要介绍了JVM的组成部分以及它们内部工作的机制和原理.当然本文只是一个简单的入门,不会涉及过多繁杂的参 ...
- python第四十五课——继承性之多重继承
演示多重继承的结构和使用 子类:Dog 直接父类:Animal 间接父类:Creature #生物类 class Creature: def __init__(self,age): print('我是 ...
- Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解
前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY <源路径> .. ...
- ethereum/EIPs-170 Contract code size limit
eip title author type category status created 170 Contract code size limit Vitalik Buterin Standards ...
- 常用的php数组函数
以下是自己比较常用的数组函数 数组元素增加减少array_pusharray_poparray_shiftarray_unshift array_splice (对数组的增删改) array_sli ...
- Docker搭建Mysql容器
转载自:http://blog.csdn.net/Mungo/article/details/78521832?locationNum=9&fps=1 本文介绍如何使用docker迅速搭建My ...
- Linux CentOS7系统中phpMyAdmin安装配置
今天介绍的是如何在Linux CentOS7系统中配置phpMyAdmin. 目录 环境准备 安装包 基本设置 网站预览 环境准备 linux centos7系统 ssh软件 php语言环境 mysq ...
- 20155220 Exp5 MSF基础应用
Exp5 MSF基础应用 一个主动攻击实践,MS08-067 首先利用msfconsole启用msf终端 然后利用search MS08-067搜索漏洞,会显示相应漏洞模块 根据上图,我们输入use ...