进程的状态
- 进程状态是什么??
进程状态,就是PCB中的一个字段,就是PCB中的一个变量,
#define NEW 1 #define RUNNING 2 #define BLOCK 3 strcut PCB { ...其他信息 int state;//进程状态 } if(PCB->state==NEW) //将进程放入运行队列 else if(PCB->state==BLOCK) //将进程放入阻塞队列
一个进程
从创建而产生至撤销而消亡的整个生命期间
,有时占有处理器执行,有时虽可运行但分不到处理器,有时虽有空闲处理器但因等待某个时间的发生而无法执行。这一切都说明进程和程序不相同,进程是活动的且有状态变化的
,于是就有了进程状态这一概念。
- Linux下常见的六种状态
下面的状态在kernel源代码里定义。
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
R运行状态(running)
并不意味着进程一定在运行中,它表明进程要么是在运行中、要么在运行队列里。
不管一个进程是否正在被处理,只要它在运行队列中
,那么它就是处于运行状态
!#include<stdio.h> int main() { while(1); return 0; }
S 浅度睡眠状态(sleeping)
一个进程处于浅度睡眠状态(sleeping),意味着该进程正在等待某件事情的完成,处于浅度睡眠状态的进程随时可以被唤醒,也可以被杀掉(这里的睡眠有时候也可叫做可中断睡眠(interruptible sleep))。
#include<stdio.h> #include<unistd.h> int main() { printf("Hello Linux\n"); sleep(100); return 0; }
浅度睡眠状态的进程是可以被杀掉的,使用kill命令将该进程杀掉。
D 深度睡眠状态(Disk sleep)
也叫不可中断睡眠状态(uninterruptible sleep),进程处于D状态,不可以被杀掉!在这个状态的进程通常会等待IO的结束。
例如,某一进程要求对磁盘进行写入操作,那么在磁盘进行写入期间,当进程压力过大时,会kill掉一部分进程,恰巧kill掉了该进程,那么如果写入成功那么OK,如果写入失败那么操作系统就要背锅。因此,为了避免这种情况就有了深度睡眠状态,进程不回被kill掉直到自己等待IO结束。
T停止状态(stopped)
在Linux当中,我们可以通过发送SIGSTOP信号使进程进入暂停状态(stopped),发送SIGCONT信号可以让处于暂停状态的进程继续运行。
例如,我们对一个进程发送SIGSTOP信号,该进程就进入到了暂停状态。
kill指令
Z僵尸状态(Zombie)
首先,我们我们知道创建进程的目的是完成某项工作,但当我进程退出时,我怎样知道该工作完成的进度,所以进程在退出时需返回一些退出信息来表示任务完成得如何!
当进程退出但是还没处理完后事时,此时处于僵尸状态。
事实上,要让父进程读取到退出PCB中的退出信息,得知子进程退出的原因,此时才能释放退出进程的PCB!
当一个进程退出了,但是退出信息还没被父进程读取,此时操作系统必然会维护这个退出进程的PCB结构不被释放,此时这个退出进程就处于僵尸状态(Z),此时会有内存泄漏的风险!
X死亡状态(dead)
收进程资源。进程相关的内核数据结构&代码和数据。
僵尸进程
个进程若是正在等待其退出信息被读取,那么我们称该进程处于僵尸状态。而处于僵尸状态的进程,我们就称之为僵尸进程。
fork函数创建的子进程在打印5次信息后会退出,而父进程会一直打印信息。也就是说,子进程退出了,父进程还在运行,并且父进程没有读取子进程的退出信息,那么此时子进程就进入了僵尸状态。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("I am running...\n");
pid_t id = fork();
if(id == 0)//child
{
int count = 5;
while(count)
{
printf("I am child...PID:%d, PPID:%d, count:%d\n", getpid(), getppid(), count);
sleep(1);
count--;
}
printf("child quit...\n");
exit(1);
}
else if(id > 0)//father
{
while(1)
{
printf("I am father...PID:%d, PPID:%d\n", getpid(), getppid());
sleep(1);
}
}
else
{
//error
}
return 0;
}
监控脚本
while :; do ps axj | head -1 && ps axj | grep test | grep -v grep;echo "****************";sleep 1;done
僵尸进程的危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态!
- 僵尸进程的退出信息被保存在task_struct(PCB)中,僵尸状态一直不退出,那么PCB就一直需要进行维护。
- 若是一个父进程创建了很多子进程,但都不进行回收,那么就会造成资源浪费,因为数据结构对象本身就要占用内存。
- 僵尸进程申请的资源无法进行回收,那么僵尸进程越多,实际可用的资源就越少,也就是说,僵尸进程会导致内存泄漏。
孤儿进程
父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”
孤儿进程被1号init进程领养,当然要有init进程回收
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("I am running...\n");
pid_t id = fork();
if(id == 0)//child
{
int count = 5;
while(1)
{
printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid(), count);
sleep(1);
}
}
else if(id > 0)//father
{
int count = 5;
while(count)
{
printf("I am father...PID:%d, PPID:%d, count:%d\n", getpid(), getppid(), count);
sleep(1);
count--;
}
printf("father quit...\n");
exit(0);
}
else
{
//error
}
return 0;
}
进程优先级
基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
查看系统进程
ps -l
PRI:代表这个进程可被执行的优先级,其值越小越早被执行。
NI:代表这个进程的nice值。
PRI与NI
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
- 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
- PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
- 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
- 所以,调整进程优先级,在Linux下,就是调整进程nice值,
- nice其取值范围是-20至19,一共40个级别
当输入的NI值小于-20时系统会自动将NI变成-20,当输入的NI值大于19时,系统会自动将NI变成19!
PRI vs NI
- 进程的nice值不是进程的优先级,但是进程nice值会影响到进程的优先级变化。
- 可以理解nice值是进程优先级的修正修正数据。
调整优先级
- 输入top启动任务管理器
- 输入r(renice)来修改NI的值
- 再输入目标进程的pid来定位
- 输入想要修改的NI值(注意不是输入PRI值)
系统允许优先级的值被改高;如果想要将值改低要用sudo或root账号
四个重要概念
竞争性
: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便有了优先级。
独立性
: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
并行
: 多个进程在多个CPU下分别同时进行运行,这称之为并行。
并发
: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
为什么优先级不能随意修改?
操作系统在调度进程时,需要较为均衡的让每一个进程都要得到调度如果用户无下限的修改优先级,会导致优先级较低的进程长时间得不到CPU的资源,会造成: 进程饥饿。
当一个进程被放在CPU上处理时,并不是一直在CPU上,过段时间后操作系统会它取下来放入其他进程!所以在一秒内,n个进程可能就已经被调度成百上千次了!