进程切换(上下文切换)
进程切换的要求
进程生命周期的信息
上下文切换图示
内核为每个进程维护了对应的进程控制块(PCB)
内核将相同状态的进程的PCB放置在同一队列
Windows进程创建API: CreateProcess(filename)
Unix进程创建系统调用: fork/exec
用fork和exec创建进程的示例
int pid = fork(); // 创建子进程
if(pid == 0) { // 子进程在这里继续
// Do anything (unmap memory, close net connections…)
exec(“program”, argc, argv0, argv1, …);
}
fork() 创建一个继承的子进程
fork()的返回值
fork()的地址空间复制
系统调用exec( )加载新程序取代当前运行进程
exec()示例代码
main()
…
int pid = fork(); // 创建子进程
if (pid == 0) { // 子进程在这里继续
exec_status = exec(“calc”, argc, argv0, argv1, …);
printf(“Why would I execute?”);
} else { // 父进程在这里继续
printf(“Whose your daddy?”);
…
child_status = wait(pid);
}
if (pid < 0) { /* error occurred */
fork()使用示例
int main()
{
pid_t pid;
int i;
for (i=0; i<LOOP; i++)
{
/* fork another process */
pid = fork();
if (pid < 0) { /*error occurred */
fprintf(stderr, “Fork Failed”);
exit(-1);
}
else if (pid == 0) { /* child process */
fprintf(stdout, “i=%d, pid=%d, parent pid=%d\n”,I,
getpid() ,getppid());
}
}
wait(NULL);
exit(0);
}
fork()的实现开销
在99%的情况里,我们在调用fork()之后调用exec()
vfork()
允许进程“加载”一个完全不同的程序,并从main开始执行(即_start)
允许进程加载时指定启动参数(argc, argv)
exec调用成功时
代码段、堆栈和堆(heap)等完全重写
wait()系统调用用于父进程等待子进程的结束
wait()系统调用的功能
进程从退出开始,到它的退出状态信息被父进程的wait/waitpid读走,在这个阶段中,进程将仍然存在于内核进程表中,这个阶段的进程的状态是终止态或称为僵尸态。而僵尸态进程称为僵尸进程,而父进程读子进程退出状态信息的动作则称为”reap”(这是一个术语,含义是收割、收走),即为子进程收尸。
进程结束执行时调用exit(),完成进程资源回收
exit()系统调用的功能:
进程终止是最终的垃圾收集(资源回收)
优先级控制
进程调试支持
定时