·什么是进程
狭义定义:进程是正在运行的程序的实例。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
·描述进程
操作系统对于进程有自己的一个描述,叫做PCB(process control block),而我们在Linux系统下的则叫做task_struct。task_struct是Linux内核的一种数据结构,使用了类似双向链表这些结构体组织起来进行管理,它会被装载到内存中并且包含着进程信息。
·task_struct中的内容
标识符 | 描述本进程的唯一标识符,用来区别其他进程。 |
状态 | 任务状态,退出代码,退出信号等。 |
优先级 | 相对于其他进程的优先级。 |
程序计数器 | 程序中即将被执行的下一条指令的地址。 |
内存指针 | 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块指针。 |
上下文数据 | 进程执行时处理器的寄存器中的数据。 |
I/O状态信息 | 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。 |
记账信息 | 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。 |
·查看进程
我们可以在Linux中写一个死循环,用另外一个终端进行查看:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
while(1)
{
sleep(1);
}
return 0;
}
ps aux后我们可以看到如下图的进程信息:
当然一般我们还是通过查看进程的pid再去所有进程中进行查找,而查看pid的命令为:getpid()。下面给一个简单的代码:
#inlcude<stdio.h>
#inlcude<sys/types.h>
#inlcude<unistd.h>
int main()
{
printf("pid:%d\n",getpid());
printf("pid:%d\n",getppid());
return 0;
}
·创建进程
在Linux中,我们使用fork()来创建进程,先看一段代码吧:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int ret=fork();
printf("proc:%d,ret:%d\n",getpid(),ret);
sleep(1);
return 0;
}
如果fork的返回值为0,就代表子进程;如果fork的返回值大于0则就代表父进程,那么对于父进程fork返回的就是子进程的ID。
·进程状态
下面简单介绍一下Linux下的几个进程状态:
运行状态(R) | 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。 |
睡眠状态(S) | 意味着进程在等待事件完成。 |
磁盘休眠状态(D) | 有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束。 |
停止状态(T) | 可以通过发送SIGSTOP信号给进程来停止进程。这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行。 |
僵尸状态(Z) | 当进程退出并且父进程没有读取到子进程退出的返回码时就会产生僵尸进程。 |
死亡状态(X) | 这个状态只是一个返回状态,无法再任务列表中看到这个状态。 |
·进程状态的修改
我们想要改变一个进程的状态或者杀死一个进程应该如何做呢?
#include<stdio.h>
int main()
{
while(1);
return 0;
}
这个进程是一直处于R状态的,我们通过ps aux | grep ./a.out查找到pid来进行杀死进程。
·僵尸进程和孤儿进程
·僵尸进程
·僵尸状态是一个比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。
·僵尸进程会以终止状态保持在进程表,并且会一直在等待父进程读取退出状态代码。
·因此,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,则子进程进入僵尸状态。
一个简单的例子:
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id<0)
{
perror("fork");
return 1;
}
else if(id>0)
{
printf("parent:%d\n",getpid());
sleep(30);
}
else
{
printf("child:%d",getpid());
sleep(30);
exit(EXIT_SUCCESS);
}
return 0;
}
我们可以看到子进程已经已经结束,而父进程还在sleep中,因此可以看到子进程已经进入Z状态。
·孤儿进程
·父进程如果提前退出,子进程就称之为“孤儿进程”。
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id=fork();
if(id<0)
{
perror("fork");
return 1;
}
else if(id==0)
{
printf("I am child,pid: %d\n",getpid());
sleep(10);
}
else
{
printf("I am parent,pid: %d\n",getpid());
sleep(3);
exit(0);
}
return 0;
}
我们会发现父进程已经退出,但是子进程依然存在,那么这个时候的子进程就是一个孤儿进程。
·进程优先级
·概念
CPU资源分配的先后顺序,就是指进程的优先权,优先权高的进程有优先执行的权利。
·查看系统进程
我们输入ps-l后会看到下面的内容:
UID:代表执行者的身份。
PID:代表这个进程的代号。
PPID:代表这个进程是由哪个进程发展衍生而来的,即父进程的代号。
PRI:代表这个进程可被执行的优先级,其值越小则越早被执行。
NI:代表这个进程的nice值。nice值为进程PRI的修正值,我们可以理解为一个进程的PRI=PRI+nice,那么通过修改nice的值,也就能达到修改进程优先级的目的。
·修改进程优先级的几种方式
执行程序的时候指定nice值,比如:nice -n -5 ./test。
对于已经存在的进程通过renice进行调整,比如:renice -5 -p PID。
用top命令进行修改,top->r->PID->nice。