进程:
1.理解进程
进程就是运行中的程序。一个运行着的程序,可能有多个进程。
进程是一个具有独立功能的程序关于某个数据集合的一次可以并发执行的运行活动,是处于活动状态的计算机程序。进程作为构成系统
的基本细胞,不仅是系统内部独立运行的实体,而且是独立竞争资源的基本实体。
对Linux来说,新进程又 fork() 与 execve() 等系统调用开始,然后执行,直到它们下达 exit() 系统调用为止。
计算机的一颗 cpu 在某一个时间点只能处理一个进程,它的做法是先使用极端的时间处理一个进程,然后将这个进程搁置,将cpu资源让给
其他进程执行。这个极端的时间称为时间片。
关于时间片的调度,在操作系统内核中,有个模块称为调度器(scheduler),它负责管理进程的执行和切换。
ps (process status) :
ps aux //BSD 风格
ps -elf //System V 风格
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 191532 4528 ? Ss Feb20 6:31 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root 2 0.0 0.0 0 0 ? S Feb20 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S Feb20 0:08 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< Feb20 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S Feb20 0:01 [migration/0]
STAT :
D 不可打断的休眠状态(通常是IO进程)
R 正在运行中在队列中可过行的
S 处于休眠状态
T 停止或者被追踪的状态
W 进入内存交换
X 死掉的进程
Z 僵死进程
<
N
L 有些页被锁进内存
s 进程的领导者(它之下有子进程)
l 多线程进程
+ 位于后台的进程
pstree :
-a 显示每个程序的完整指令
-c 不适用精简标示法
-p 显示 pid
-u 显示用户
进程的属性:
一个进程是一个程序的一次执行过程,程序是静态的,它是一些保存在磁盘上的可执行的代码和数据集合,进程是一个动态的概念。一个进程由如下元素组成:
1.程序的读取上下文,它表示程序读取执行的状态
2.程序当前的执行目录
3.程序服务的文件和目录
4.程序的访问权限
5.内存和其他分配给进程的系统资源
一个进程在内存里存有3部分数据,就是 '数据段',‘堆栈段',’代码段‘。代码段就是程序代码的数据,如果有数个进程运行相同的一个程序,它们就可以使用
同一个代码段。而数据段则存放着程序的全局变量,常数以及动态数据分配的数据空间。堆栈段存放的就是子程序的返回地址,子程序的参数及程序的局部变量。堆栈
段包括在进程控制块PCB(Process Conroller Block),PBC 位于进程核心堆栈的底部,不需要额外分配空间。
2.进程管理
1.进程的状态
用户状态
内核状态
内存中就绪
内存中睡眠
就绪且换出
睡眠且换出
被抢先
创建状态
僵死状态
睡眠等待状态分为:可中断和不可中断的等待状态
运行状态(task_running) : 当进程正在被 cpu 执行,或者已经准备就绪,随时可由调度程序执行,则称为该进程出于运行状态(running)。若
此时进程没有被 cpu 执行,则称为其出于就绪运行状态。
可中断睡眠状态(task_interruptible) : 当进程处于可中断等待(睡眠)状态时,系统不会调度该进程执行。当系统产生一个中断或者释放了进程正在
等待的资源或者进程收到一个信号,都可以唤醒进程到就绪状态(即可运行状态)
不可中断的睡眠状态(task_uninterruptible) : 除了不会因为收到信号而被唤醒,该状态与可中断睡眠状态类似。但该状态的进程只有被使用 wake_up()
函数明确唤醒时,才能转换到可运行的就绪状态。该状态通常在进程需要不受干扰的等待,或者等待的事件会很快发生时使用。
暂停状态(task_stopped) : 当进程收到信号 SIGSTOP, SIGTSTP,SIGTTIN 或者 SIGTTOU 时,就会进入暂停状态。可向其发送 SIGCONT 信号,让进程
转换到可运行状态。进程在调试期间接收到任何信号均会进入该状态。
僵死状态(task_zombie) : 当进程已经停止运行,但其父进程还没有调用 wait() 询问其状态时,该进程就出于僵死状态。为了父进程能够获取其停止运行的
信息,此时子进程的任务数据结构信息还需要保存着。一旦父进程调用了 wait(),获取了 子进程的信息,则出于该状态进程的任务数据结构就可以释放。
当一个进程的运行时间片用完,系统就会使用调度程序强制切换到其他的进程去执行。另外,如果进程在内核态执行时,需要等待系统的某个资源,此时该进程
就会调用 sleep_on() 或者 interruptible_sleep_on(), 自愿放弃cpu的使用权,而让调度程序去执行其他进程。进程则进入睡眠状态(task_uninterruptiable
或者 task_interruptible)。
只有当进程从 '内核运行态' 转移到 '睡眠状态' 时,内核才会进行进程切换操作。在内核态运行的进程不能被其他进程抢占,而且一个进程不能改变另外一个进程的状态。
为了避免进程切换时造成内核数据错误,内核在执行临界区代码时会禁止一切中断。
2.shell 命令执行
内置命令:shell 内建,由 shell 执行,不需要派生新的进程。
外部命令: 分2种,二进制代码或 shell 脚本。对于外部命令,shell 会创建一个新的进程来执行。当命令的进程运行时,默认 shell 将等待直到该进程结束。
为了执行外部的二进制命令,需要一种机制,以允许子进程转换为将要被执行的命令。Linux 调用 exec 可以做到这些,它允许一个进程用其他命令的可执行
代码覆盖自己。二进制代码需要由磁盘装入内存执行。shell 解释器出去会调用 fork 自身的一个拷贝,然后用 exec 系列函数来执行外部命令,这样外部命令就
取代了先前的 fork 的子 shell。
shell 脚本的执行与二进制文件略有不同。对于 shell 脚本而言,shell 解释程序会 fork 一个子 shell 进程,子shell 进程会检查脚本的第一行(如
#!/bin/bash),找到用来执行脚本的解释器程序,然后装入这个解释程序,由它执行脚本程序。
3.进程与任务调度
启动进程主要有2个途径:
1.手工启动
1.前台启动
2.后台启动
2.调度启动
3.信号
信号的基本概念:
1.用户输入命令,在shell下启动一个前台进程
2.用户按下 ctrl + C 快捷键,这个键盘输入产生一个硬件中断
3.如果 cpu 当前正在执行这个进程的代码,则该进程的用户控件代码暂停执行,cpu 从用户态切换到内核态处理硬件中断
4.终端驱动程序将 ctrl + C 解释成一个 SIGINT 信号,记在该进程的 PBC 中
5.当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理 PBC 中记录的信号,发现有一个 SIGINT 信号待处理,
而这个信号的默认处理动作是终止进程,所以直接终止进程,而不再返回它的用户控件代码执行。
ctrl + c 产生的信号只能发送给前台进程,shell 可以同时运行一个前台进程和任意个后台进程。信号相对于进程的控制流程来说是异步的。
信号处理的动作:
1.默认的处理动作
2.忽略此信号
3.捕获信号
4.Linux 的第一个进程 init
init 是 Linux 系统执行的第一个进程,进程ID 为1,是系统所有进程的起点,主要用来执行一些开机初始化脚本和监视进程。Linux系统在完成
内核引导以后,就开始运行 init 程序,init 程序需要读取配置文件 /etc/inittab 。inittab 是一个不可执行的文件.
inittab 配置文件每行的基本格式如下:
id:runlevels:action:process
id : 1~2个字符,配置行的唯一标识,在配置文件中不能重复
runlevels : 配置行适用的运行级别,这里可以有多个运行级别
Linux 有7个运行级别:
L0:关机
L1:单用户字符界面
L2:不具备忘了文件系统(NFS)功能的多用户字符界面
L3:具有网络功能的多用户字符界面
L4:保留不用
L5:具有网络功能的图形用户界面
L6:重启系统
action:
respawn
wait
once
boot
bootwait
off
ondemand
initdefault
sysinit
powerwait
powerfailnow
ctrlaltdel
kbrequest
process : 为 init 执行的进程,这些进程都保存在目录 /etc/rc.d/rcX 中,其中 X 代码运行级别,rc程序接收X参数,然后运行 /etc/rc.d/rc.X 下面的程序。
id:5:initdefault: // 表示当前默认运行级别为5
si::sysinit:/etc/rd.c/rc.syinit // 启动时执行 /etc/rd.c/rc.syinit 脚本
15:5:wait:/etc/rc.d/rc 5 // 当前运行级别为5时,以5为参数 运行 /etc/rc.d/rc 脚本,init 将等待其返回。
ll /etc/rc.d/rc5.d
lrwxrwxrwx. 1 root root 20 Nov 21 2014 K50netconsole -> ../init.d/netconsole
lrwxrwxrwx 1 root root 17 Jun 12 2016 S10network -> ../init.d/network
lrwxrwxrwx 1 root root 22 Apr 11 2017 S20cloudmonitor -> ../init.d/cloudmonitor
这些文件都是符号链接,以S打头的标识启动该程序,以K打头的标识终止该程序,后面的数字标识执行顺序,数字越小越先执行,剩下的标识程序名。系统启动或者
切换到该运行级别时,会执行以S打头的程序,系统切换到该运行级别的时候,会执行以K打头的程序。这个目录下的程序可以通过 chkconfig 管理。
6.调度系统任务
cron : 用于调度重复性系统任务, 文件位置 /var/spool/cron/crontabls, 访问控制的文件 /etc/cron.d/cron.allow, /etc/cron.d/deny
crontab -e 编辑 crontab 文件
ll /var/spool/cron/ 验证 crontab 文件是否存在
crontab -u 用户 -l 查看 crontab 文件
crontab -u 用户 -r
/etc/cron.d/cron.deny 将用户添加到该文件,拒绝访问
/etc/cron.d/cron.allow 将用户添加到该文件,允许访问
* * * * *
分 时 日 月 周
在 crontab 时间段使用特殊字符遵守以下规则:
1.使用空格分割每个字段
2.使用逗号分割多个值
3.使用连字符指定某一个范围
5.使用星号作为通配符包括所有的可能值
6.使用 # 注释
控制对 crontab 命令的访问:
我们可以使用 /etc/cron.d 下面的两个文件控制crontab命令的访问:cron.deny 和 cron.allow。这些文件只允许特定的用户执行 crontab 命令任务。
例如创建,编辑,显示或者删除。按照下面的方式协同工作:
1.如果存在 cron.allow, 只有此文件列出的用户可以操作
2.如果不存在 cron.allow,则所有的用户都可以提交 crontab 文件(cron.deny 列出的用户除外)
3.如果 cron.allow,cron.deny 都不存在,则运行 crontab 命令需要超级用户权限
at : 用于在特定时间调度单个系统任务, 文件位置 /var/spool/cron/atjobs, 访问控制文件 /etc/cron.d/at.deny
at 创建
atq 显示 at 队列
7.进程的窗口 /proc
Linux 内核提供了一种 /proc 文件系统,在运行时访问内核内部数据结构,改变内核设置的机制。
1.proc --- 虚拟文件系统
/proc 文件系统是一种内核和内核模块用来向进程发送信息的机制(所以叫做 /proc)。这个伪文件系统让你可以和内核内部数据结构进行交互,获取进程
有关的信息,在运行中(onthefly) 改变设置(通过改变内核参数)。与其他文件系统不同,/proc 存在于内存之中,而不在硬盘上。如果你查看文件 /proc/moounts
(和 mount 命令一样列出所有已经加载的文件系统),会看到其中一行是这样的:
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
/proc 由内核控制,没有承载 /proc 的设备。因为 /proc 主要存放由内核控制的状态信息,所以大部分这些信息的逻辑位置位于内核控制的内存。对 /proc 进行一次
'ls -l',可以看到大部分文件都是 0 字节大的。不过查看这些文件的时候,确实可以看到一些信息。这怎么可能?这是因为 /proc 文件系统和其他常规的文件一样,把
自己注册到了虚拟文件系统层(VFS)了。
然后,直到当 VFS 调用它,请求文件,目录的 i-node 的时候,/proc 文件系统才根据内核中的信息建立相应的文件和目录。
如果系统中还没有加载 proc 文件系统,可以通过下面命令加载 proc 文件系统:
mount -t proc proc /proc
/proc/cpuinfo CPU 信息
/proc/meminfo 物理内存,交换空间信息
/proc/mount 加载的文件系统列表
/proc/devices 可用设备的列表
/proc/filesystems 被支持的文件系统列表
/proc/modules 已加载的模块
/proc/version 内核版本
/proc/cmdline 系统启动时输入的内核命令行参数
2.有关运行中的进程信息
/proc 文件系统可以用于获取运行中的进程信息。在 /proc 中有一些编号的子目录。每个编号的目录对应一个进程id(PID)。这些目录中包含可以提供有关进程的状态和
环境的重要细节信息的文件。
cmdline 进程启动调用的命令行
environ 进程的环境变量
status 进程的状态
cwd 指向进程当前工作目录的符号链接
exe 运行进程的可执行程序
root 被这个进程看做是更目录的目录(通常是 '/')
fd 包含指向进程使用的文件描述符的链接
cpu 仅在运行 SMP 内核时出现,里面是按 cpu 划分的进程时间
/proc/self 是一个有趣的子目录,它使得程序可以方便的使用 /proc 查找本进程信息。/proc/self 是一个连接到 /proc 中访问 /proc 的进程所对应
的PID 的目录的符号链接。
3.通过 /proc 与内核交互
上面讨论的大部分 /proc 是只读的。而实际上 /proc 文件系统通过 /proc 中可读写的文件,创造了对内核的交互机制。写这些文件可以改变内核的状态,要慎重。
/proc/sys 目录存放了所有可读写的文件目录,可以用于改变内核行为。
/proc/sys/kernel 这个目录包含反通用内核行为的信息
/proc/sys/ketnel/{domainname,hostname} 存放着机器/网络的域名和主机名。
/proc/sys/net 这个目录中的文件可用于修改机器/网络的网络属性
8.Linux 线程
线程是共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。在2个普通进程间进行切换,内核准备从一个进程的上下文切换到另外一个进程
的上下文,需要花费很大的开销。这里上下文切换的主要任务是保存老进程的cpu状态,并加载新进程的保存状态,用新进程的内存印象替换老进程的内存印象。线程允许你的进程
在几个正在运行的任务之间进行切换,而不必执行完整的上下文。
进程的窗口 /proc :