进程基本介绍
Posted yumoz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了进程基本介绍相关的知识,希望对你有一定的参考价值。
进程概念
观点一:程序的一个执行实例,正在执行的程序等。
内核观点的概念:担当分配系统资源的实体。
进程描述
怎么样描述进程呢?进程信息被放在一个叫做**进程控制块(process control block,PCB)**的数据结构中,可以理解为进程属性的集合。在Linux操作系统下PCB是task_struct(Linux中描述进程的结构体)。
进程查看
使用命令ls /proc
查看Linux系统文件下的进程信息
进程创建
fork函数:
- fork函数有两个返回值;
- fork执行后,父进程和子进程代码共享,数据各自开辟空间,私有一份。
思考下面代码执行结果:
int main()
{
pid_t id = fork();
printf("hello yumoz\\n");
sleep(1);
return 0;
}
代码执行结果:
原因就是fork之后,创建了子进程,子进程和父进程都去执行打印语句,于是打印了两次。为了避免fork之后程序代码执行两次的情况发生,我们先去了解一下fork函数的基本知识。
fork : 创建一个子进程;
头文件:#include<unistd.h>
创建方式:pid_t fork(void);
返回值:如创建子进程成功,父进程返回子进程的PID,返回0给子进程。如果失败,父进程返回-1,没有子进程被创建。
所以,fork创建子进程后需要进行分流(if判断)。分流的目的是让子进程和父进程分别去完成不同的任务。
int main()
{
pid_t id = fork();
if(id < 0)
{
printf("create error\\n");
return 1;
}
else if(id == 0) //子进程
{
printf("I am child process\\n");
}
else //父进程
{
printf("I am parent process\\n");
}
sleep(1);
return 0;
}
进程状态
首先我们列出进程的几种状态:
- 运行态:该进程正在运行。
- 就绪态:进程做好准备,只要有机会就开始执行。
- 阻塞、等待状态:进程在某些事件发生前不能执行,如I/O操作完成。
- 新建态:进程已经创建,但是没有将此进程加入到可执行队列中。通常是进程控制块已经创建,但是还没有加载到内存中的新进程。
- 退出态:操作系统从可执行进程组中释放出的进程,或是因为它自身停止了,或者是因为某种原因被取消。
下面对上面几种状态进程一个总结,首先看一个内核代码(只需要简单看看):
/*
* 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 *task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"T (tracing stop)", /* 8 */
"Z (zombie)", /* 16 */
"X (dead)" /* 32 */
};
说明,看到上述代码,我们可以总结如下状态:
- R(running) 运行状态:并不意味着程序一定在运行中,它表明进程要么是在运行状态要么是在运行队列中。也就是可被调度。如果一个CPU,可以同时存在多个R状态的进程(因为R表示的是运行或者就绪状态)。
- S(sleeping) 睡眠状态:意味着进程在等待事件完成(或称之为可中断睡眠、浅度睡眠),用来等待某种事情发生,随时可以被唤醒或杀掉。
- D(disk sleep) 磁盘休眠状态:或称之为不可中断睡眠状态,在这个状态的进程通常会等待I/O的结束。(或者称之为深度睡眠,表示改进程不会被杀掉,即便是操作系统也不能被杀掉,除非自动唤醒);
- T(stopped) 停止状态:可以发送SIGSTOP信号给进程来停止进程。此时被暂停的进程可以通过发送SIGCONT信号让进程继续执行。
- X(dead)死亡状态:这个状态知识一个返回状态,你不会在任务列表中看到此状态
- Z (zombie) 僵尸状态:当子进程退出,并且父进程没有读到子进程的退出的返回代码就会产生僵尸进程。
僵尸进程
僵尸状态是一个很特殊的状态,从系统层面分析:进程退出,曾经申请的资源并不是立即被释放掉的,而是要暂存一段时间,供OS(或父进程)进行读取,称为僵尸状态。这么深涩难懂吗?并不是,继续往下看。
首先通过一个例子说明僵尸进程:
int main()
{
pid_t id = fork();
if(id == 0)
{
int count = 5;
while(count){
printf("do child process! count:%d \\n",count--);
sleep(1);
}
printf("child quit!\\n");
exit(1);
}
else if(id > 0)
{
while(1)
{
printf("do father process!\\n");
sleep(2);
}
}
else
{
printf("fork error\\n");
}
}
通过上述代码可以使用脚本键控进程状态:
while :; do ps aux | head -1 && ps aux | grep myfork | grep -v grep;sleep 1; echo "##根据需要打印##"; done
发现子进程先退出,之后父进程没有读到子进程的退出信号,子进程成了僵尸进程。那么了解到这了,一些僵尸进程的知识还是必须要知道的。下面列出来:
- 只要子进程退出,父进程还在运行,但父进程没有读到子进程状态,子进程进入Z状态。
- 僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取状态代码。
僵尸进程的危害
- 进程的退出状态必须被维持下去,因为他需要告诉父进程一些信息。但如若父进程一直读不到,那么子进程就一直处于Z状态。
- 维护退出状态需要数据维护,他也属于进程的基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,那么PCB一直都要维护。
- 如果一个父进程创建了很多个子进程,子进程都成了僵尸进程,无法回收,就会造成内存资源浪费。因为数据结构对象本身就是在占用内存的资源。
- 僵尸进程还会导致内存泄漏等。
孤儿进程
父进程先退出,子进程没退出,则称之为“孤儿进程”。
孤儿进程最终会被1号init进程领养。
先看一段代码,了解孤儿进程:
int main()
{
pid_t id = fork();
if(id > 0)
{
printf("do child process!pid: %d ppid:%d \\n", getpid(),getppid());
sleep(3);//父进程先退出
exit(0);
}
else if(id == 0)
{
while(1)
{
printf("do father process!...pid:%d , ppid: %d ...\\n",getpid(),getppid());
sleep(1);
}
}
else
{
printf("fork error\\n");
}
return 0;
}
杀掉孤儿进程:kill -9 进程编号
进程优先级
UID:执行者身份
PID:进程代号
PPID:进程的父进程代号
PRI:此进程的优先级,值越小越早被执行
NI:进程的nice,表示进程可被执行的优先级的修正系数值,取值范围-20至19
说明:
nice值为负,表示该进程优先级值会变小,即其优先级会变高,越快被执行。反之,同理。
调整进程优先级,在Linux下,就是调整进程nice值。
以上是关于进程基本介绍的主要内容,如果未能解决你的问题,请参考以下文章