Linux内核源码分析 (A.2)进程原理及系统调用
一、进程
-
操作系统的作用:作为硬件的使用层,提供使用硬件资源的能力,
-
进程的作用:作为操作系统使用层,提供使用操作系统抽象出的资源层的能力
-
进程、线程和程序的区别:进程指计算机中已运行的程序。进程本身不是基本的运行单位,而是线程的容器。
程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行
实例 -
Linux内核中的进程:Linux内核把进程叫做任务(task),进程的虚拟地址空间可分为用户虚拟地址空间和内核虚拟地址空间,所有进程共享内核虚拟地址空间,每个进程都有独立的用户虚拟空间
-
Linux内核进程的特殊形式:没有用户虚拟地址空间的进程叫内核线程,共享用户虚拟地址空间的进程叫用户线程,共享同一个用户虚拟地址空间的所有用户线程叫线程组。
-
C语言标准库进程&Linux内核进程文章来源:https://www.toymoban.com/news/detail-470671.html
C语言标准库进程 Linux内核进程 包括多个线程的进程 线程组 只有一个线程的进程 任务或进程 线程 共享用户虚拟地址空间的进程 -
查询进程状态文章来源地址https://www.toymoban.com/news/detail-470671.html
-
ps -aux
查询内存中的瞬时进程信息- USER :进程的所属用户,
- PID :进程的进程ID号,
- %CPU :进程占用的 CPU资源 百分比,
- %MEM :进程占用的 物理内存 百分比,
- VSZ :进程使用掉的虚拟内存量 (Kbytes) ,
- RSS :进程占用的固定的内存量 (Kbytes) ,
-
TTY :与进程相关联的终端(tty),
?
代表无关,tty1-tty6
是本机上面的登入者程序,pts/0
表示为由网络连接进主机的程序。 - STAT :进程的状态;R->运行->Runnable;S->可中断睡眠->Sleeping;D->不可中断睡眠->Uninterruptible sleep;I->空闲->Idle;Z->僵死->Zombie(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放);T->终止->Terminate;s->进程的领导者;等等…
- START :进程开始创建的时间 。
- TIME :进程使用的总cpu时间,
- COMMAND : 进程对应的实际程序。
-
top
动态显示内存中的进程信息- PR : 进程优先级
- NI : nice 值, 负值表示最高优先级,正值表示 低级优先级
- VIRT : 进程使用的虚拟内存总量,单位为 KB
- SHR : 共享内存大小,单位 KB
- 其他参数在上面已重复提到。
-
二、进程的生命周期
-
进程的状态
- 创建状态:创建新进程
- 就绪状态:进程获取可以运作所有资源及准备相关条件
- 执行状态:进程正在CPU中执行操作
- 阻塞状态:进程因等待某些资源而被跳出CPU
- 终止状态:进程消亡
-
进程状态之间的转换
-
Linux内核通过提供API函数来设置进程的状态
- TASK_RUNNING:可运行状态或者就绪状态
- TASK_INTERRUPTIBLE:可中断睡眠状态,又叫浅睡眠状态
- TASK_UNINTERRUPTIBLE:不可中断状态,又叫深睡眠状态
- __TASK_STOPPED:终止状态
- EXIT_ZOMBIE:僵尸状态
-
通过API表示进程状态转化
三、task_struct数据结构
- Linux内核涉及进程和程序的所有算法都围绕一个名为
task_struct
的数据结构建立,该结构定义在include/linux/sched.h
中。task_struct
包含很多成员,将进程与各个内核子系统联系起来。下面是Linux5.6.18
中关于task_struct
结构体的注释。
四、进程优先级
- 限期进程的优先级比实时进程高。实时进程的优先级比普通进程高。
- 限期进程的优先级是-1
- 实时进程的优先级是1-99,优先级数字越大,表示优先级越高
- 普通进程的静态优先级为:100-139,优先级数值越小,表示优先级越高,可通过修改
nice
值改变普通进程的优先级,优先级等于120+nice
,很显然:nice
值的取值范围是-20~19
。
- 各种优先级与进程之间的关系
- 四种优先级
- 关系对比
- 四种优先级
五、系统调用
- 当运行应用程序的时候,调用
fork()
、vfork()
和clone()
函数就是系统调用。系统调用就是应用程序如何进入内核空间执行任务,程序使用系统调用执行一系列操作:比如创建进程、文件IO等等。具体如下图所示:
六、内核线程
- 内核线程是直接由内核本身启动的进程。内核线程实际上是将内核函数委托给独立的进程,与系统中其他进程并发地执行(实际上,也并行于内核自身执行)。内核线程经常称之为(内核)守护进程。他们用于执行下列任务。
- 周期性地将修改的内存页与页来源块设备同步(例如:使用mmap的文件映射)
- 如果内存页很少使用,则写入交换区。
- 管理延时动作(deferred action)。
- 实现文件系统的事务日志。
- 内核线程中,
task_struct
数据结构里面有一个成员指针mm
的值为NULL
,它只能运行在内核空间。下面是内核创建函数(位于kernel/fork.c
):/* * Create a kernel thread. */ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) { struct kernel_clone_args args = { .flags = ((lower_32_bits(flags) | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL), .exit_signal = (lower_32_bits(flags) & CSIGNAL), .stack = (unsigned long)fn, .stack_size = (unsigned long)arg, }; return _do_fork(&args); }
七、退出进程
- 退出进程有两种方式:
- 进程主动终止:从
main()
函数返回,链接程序会自动添加到exit()
系统调用;或者主动调用exit()
系统调用。 - 进程被动终止:进程收到一个自己不能处理的信号;或者进程收到
SIGKILL
等终止信息。
- 进程主动终止:从
- 下面是退出进程的系统调用,函数位于
kernel/exit.c
SYSCALL_DEFINE1(exit, int, error_code) { do_exit((error_code&0xff)<<8); }
到了这里,关于《Linux内核源码分析》(2)进程原理及系统调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!