一、什么是进程
通常我们了解到的概念,进程就是一个正在执行的程序。但简简单单的几个字,让人感到困惑,进程到底是什么样的呢?
举一个简单的例子:
学校是如何管理学生的呢?当然是通过对每个学生的信息进行管理。
这些信息就是一个学生的属性,例如
//每个学生的属性都可以用一个结构体来保存,那么对这些包含学生信息的
//结构体的管理,就实现了对学生的管理。
struct students
{
char name[20];
char sex[5];
int age;
//等等各种有关于一个学生的信息
}
从上述例子得出,我们对任何事物的管理都可以用此方式,将具体事物的属性提取出来进行管理,这种实现方式就是先描述,再组织。
在操作系统中,进程的各种信息被放入一个叫做程序控制块的数据结构中,可以称之为进程的属性集合。即PCB(process control block),在Linux操作系统下的PCB是:task_struct。
综上,进程=可执行程序+内核数据结构。
task_struck的内容:
标示符: 描述本进程的唯一标示符,用来区别其他进程。
状态: 任务状态,退出代码,退出信号等。
优先级: 相对于其他进程的优先级。
程序计数器: 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息
二、查看进程
1.通过 /proc系统文件夹查看
例:ll /proc/1 查看的是bash
2.通过top/ps等来获取
3.通过系统调用的方式获取进程标识符
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("pid: %d\n", getpid());//获取该进程的pid
printf("ppid: %d\n", getppid());//获取父进程的pid
return 0;
}
三.进程状态
1.基本描述
运行态:进程在运行队列中,随时可以被cup调度
终止态:进程运行结束,等待操作系统闲时回收资源
阻塞态:进程不具备运行条件,正在等待某个事件的完成。(当进程向cpu申请显示器资源时,有其他进程也在使用显示器资源,操作系统就会将该进程放入显示器资源的等待队列当中,阻塞式等待该资源空闲)
挂起态:当内存不足并且该进程短时间内不会被调度,操作系统就会把该进程的代码和数据置换到磁盘上,所以内存不足时往往伴随着磁盘的高频访问。
2.Linux下的进程状态
操作系统内核对状态的定义:
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): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列
里。
S睡眠状态(sleeping) :意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠。
D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
Z僵尸状态
四、僵尸进程、孤儿进程
1.僵尸进程
上面提到的Z状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。
例:
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id<0)
{
printf("fork error");
}
else if(id==0)
{
//子进程运行五秒退出
printf("I'm child\n");
sleep(5);
exit(1);
}
else
{
//父进程一直运行,不等待子进程
printf("I'm parent\n");
sleep(30);
}
return 0;
}
上述代码发现,父进程不进行等待子进程退出,会导致子进程僵尸
僵尸进程的危害:
1.操作系统一直维护该进程的pcb
2.一直占用内存
2.孤儿进程
父进程先退出,子进程就称之为“孤儿进程”
孤儿进程会被1号init进程领养,由init进程回收。
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id<0)
{
printf("fork error");
}
else if(id==0)
{
printf("I'm child\n");
sleep(30);
}
else
{
//父进程直接退出
printf("I'm parent\n");
exit(1);
}
return 0;
}
五、进程优先级
1.概念
cpu资源分配的先后顺序,就是指进程的优先权(priority)。
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
2.查看系统进程
使用ps -l 命令
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
PRI and NI
PRI,进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高
NI:即nice值,其表示进程可被执行的优先级的修正数值
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
所以,调整进程优先级,在Linux下,就是调整进程nice值
nice其取值范围是-20至19,一共40个级别
使用 top 命令修改nice值
- top
- 进入top后按“r”——>输入进程的pid——>输入nice值
3.其他概念
竞争性:当进程数量较多,cpu资源过少甚至只有一个时,为了获取资源,就产生了竞争性
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
并发:多个进程在一个cpu的情况下,切换运行,保证在一段时间内所有进程的能得到推进
并行: 多个进程在多cpu下,分别同时运行,互不干扰