1.描述一下进程的三个状态,以及相互转换
就绪态:进程所需的资源已经全部准备好,等待系统调度进入执行态。
执行态:进程占用CPU资源运行进程,进程运行结束或时间片用尽或缺少资源时会退出执行态
等待态:进程需要资源没有全部就绪,进程进入等待态进行等待,当所有资源全部就绪时进入就绪态。
进程状态转换:
2.进程控制块 PCB
PCB(Progress Control Block:进程控制模块)
PCB是OS进行进程管理的工具,每个进程在被创建时,都会开辟一段内存空间存放与此进程相关的PCB结构。
PCB是操作系统中最重要的记录型数据结构,它记录了用于描述进程进展情况以及控制进程运行所需的全部信息。
PCB是进程存在的唯一标志,在Linux系统中PCB存放在task_struct结构体中。
2.描述一下守护进程、孤儿进程、僵尸进程的概念
孤儿进程:如果父进程先退出,子进程还没退出,那么子进程将被init进程收养,这时子进程的父进程就是init进程(1号进程),并由init进程完成对他们的状态收集工作。
僵尸进程:进程终止后不会立刻消失,而是进入僵死状态(zombie),直到告知父进程自己终止后,才能完全消失。如果一个进程已经终止了,但是其父进程还没有获取其状态,那么这个进程就称之为僵尸进程。僵尸进程还会消耗一定的系统资源,并且还保留一些概要信息供父进程查询子进程的状态。一旦父进程得到想要的信息,僵尸进程就会彻底结束消失。
守护进程:守护进程(daemon),是一种运行在后台的特殊进程(也是孤儿进程),它独立于控制终端 ,并周期性地执行某项任务或等待处理某些发生的事件,仅在系统关闭时才终止。 守护进程可以由一个普通的进程按照守护进程的特性改造而来。其改造过程如下:
3.使用fork函数得到的子进程是父进程的一个复制品, 它从父进程处继承了哪些东西?
子进程从父进程处继承了整个进程的地址空间,地址空间包括:
进程上下文,进程堆栈,打开的文件描述符,信号控制设定,进程优先级,进程组号等等。
4.例02_fork_3.c、例04_waitpid.c、例05_atexit.c三个进程的代码截图及运行结果截图
fork_3.c:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
pid_t pid;
int length = 0;
char buf[] = "a write to stdout\n";
length = write(1, buf, strlen(buf));
if(length != strlen(buf))
{
printf("write error\n");
}
printf("before fork\n");
pid = fork();
if(pid < 0)
{
perror("fork");
}
else if(pid == 0){
printf("in son process\n");
}else{
sleep(1);
printf("in father process\n");
}
return 0;
}
解释:
-
当以交互模式运行程序时,是行缓冲,所以"before fork\n"在执行fork前就已经被清空。而其他方式运行程序时则都是全缓冲
-
由于写入文件的缓冲方式是全缓冲,所以在打印"before fork\n"的时候并没有清空缓冲区,fork函数在执行时,将缓冲区的内容一起复制给了子进程,所以子进程缓冲区内也有"before fork\n"内容,在这两个程序结束时。进行清空缓冲区操作,都输出了"before fork\n"内容。
-
write函数是系统调用,不带缓冲。
waitpid.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid;
pid=fork();
if(pid < 0)
perror("fork");
if(pid == 0)
{
int i = 0;
for(i=0;i<5;i++)
{
printf("this is son process\n");
sleep(1);
}
_exit(2);
}
else
{
waitpid(pid, NULL, 0);
printf("this is father process\n");
}
return 0;
}
解释:等待指定子进程结束。
atexit.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void clear_fun1(void)
{
printf("perform clear fun1 \n");
}
void clear_fun2(void)
{
printf("perform clear fun2 \n");
}
void clear_fun3(void)
{
printf("perform clear fun3 \n");
}
int main(int argc, char *argv[])
{
atexit(clear_fun1);
atexit(clear_fun2);
atexit(clear_fun3);
printf("process exit 3 sec later!!!\n");
sleep(3);
return 0;
}
解释:存放清理函数的空间类似于栈,所以后注册函数在退出时会先执行。