1:PCB进程控制块
Task_struct结构体,也就是PCB,存放着这个进程所需要的所有资源的结构的描述。
PCB管理:链表、树、哈希。
2:进程生命周期
六种状态:就绪态、运行态、停止态、深度睡眠态、浅睡眠态、僵尸态。
前三个好理解,主要是后三个:
深睡眠:进程处于睡眠态(调用sleep),等到资源到位,就可以被调度(变成就绪态TASK_RUNNING)。
浅睡眠:进程处于睡眠态(调用sleep),等到资源到位,或者收到信号,就可以被调度(变成就绪态TASK_RUNNING)。
僵尸态:父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE
,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait()
系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。
正常的进程睡眠都是浅睡眠,但是内核中有一些进程处于睡眠态不希望被信号打断,那么它就会处于深睡眠状态。
3:folk创建子进程
举个例子:
int main() { fork(); printf("hello "); fork(); printf("hello "); while (1); return 0; }
打印几个hello?
一分为2,打印2次;2分为4,打印4次;一共6次。
fork()函数的返回值是返回两次的,在父进程中返回子进程的pid,在子进程中返回0。利用分支识别:
#include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> int main(){ pid_t pid; pid = fork(); if(pid==-1){ /* 创建不成功 */ perror("Can't creat new process"); exit(1); } else if(pid==0){ /* pid==0,子进程运行代码 */ printf("a "); } else { /* 父进程运行代码 */ printf("b "); } /* 父子进程都运行的代码 */ printf("c "); while(1); }
Linux中编译执行:gcc 1.c -o 1
再:./1
结果:
b
c
a
c
分析:
父进程返回子进程pid(不为0)输出b,再输出c。
子进程返回0,输出a,再输出c。
4:子死父清场
例如:
#include <stdio.h> #include <sys/wait.h> #include <stdlib.h> #include <unistd.h> int main(void) { pid_t pid,wait_pid; int status; pid = fork(); if (pid==-1) { perror("Cannot create new process"); exit(1); } else if (pid==0) { printf("child process id: %ld ", (long) getpid()); pause(); _exit(0); } else { #if 1 /* define 1 to make child process always a zomie */ printf("ppid:%d ", getpid()); while(1); #endif do { wait_pid=waitpid(pid, &status, WUNTRACED | WCONTINUED); if (wait_pid == -1) { perror("cannot using waitpid function"); exit(1); } if (WIFEXITED(status)) printf("child process exites, status=%d ", WEXITSTATUS(status)); if(WIFSIGNALED(status)) printf("child process is killed by signal %d ", WTERMSIG(status)); if (WIFSTOPPED(status)) printf("child process is stopped by signal %d ", WSTOPSIG(status)); if (WIFCONTINUED(status)) printf("child process resume running.... "); } while (!WIFEXITED(status) && !WIFSIGNALED(status)); exit(0); } }
照样gcc 2.c -o 2
./2
输出:
ppid:5715
child process id: 5716
(别结束运行)
在另一终端查看父子进程:命令ps -lA
找到父子进程状态:
然后:
kill -9 5716
再查看状态:
子进程转为僵尸态了。
以上是在#if 1 的情况下
如果修改为 #if 0
那么再次编译运行 结果是:
child process id: 5901
(也别结束运行)
再另一个终端查看父子进程
kill子进程,发现运行的2程序结束运行了,且报告了原因
可以看出父进程可以通过waitpid()函数回收子进程的task_struct结构。
5:总结
这张六种状态图蛮重要,记录下来。
我是小狼程序员,希望在自己在计算机方面的知识懂的越来越多,技术越来越熟练。
欢迎大家加我qq交流:809291807
目前交流方向可以有:数据结构与算法、计算机操作系统、C++编程、Java编程、Linux等。