Linux进程有7种基础状态(两种running算一种),除了traced都可以用$ps命令查看,$ps可以查看的进程状态如下,更多进程状态信息参见Linux Process VS Thread VS LWP R running or runnable (on run queue) D uninterruptible sleep (usually IO) S interruptible sleep (waiting for an event to complete) T stopped, either by a job control signal or because it is being traced. W paging (not valid since the 2.6.xx kernel) X dead (should never be seen) Z defunct ("zombie") process, terminated but not reaped by its parent.
多进程代码区模型(其他区参见copy-on-write):
#include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> getpid()/getuid()/getgid() //获得PID/UID/GID fork()/vfork() //创建子进程 exec() family //替代子进程 atexit()/on_exit()/exit()/_exit()/_Exit() //退出子进程 wait()/waitpid() //获得子进程退出状态fork()创建的子进程继承父进程的有:
实际用户ID,实际组ID,有效用户ID,有效组ID附属组ID进程组ID会话ID控制终端设置用户ID标志和设置组ID标志当前工作目录根目录文件模式和安排信号屏蔽和安排对任一打开fd的close-on-exec环境连接的共享存储段存储映像资源限制与父进程有区别的有
fork的返回值PIDPPID子进程的tms_utime,tms_stime,tms_cutime,tms_ustime被设置为0不继承文件锁子进程未处理闹钟被清除子进程未处理信号集设置为空集fork()产生的所有进程共享代码区,copy-on-write其他区)
fork()之前的代码, 由parent执行一次fork()之后的代码, 由父子进程各执行一次fork()的返回值由父子进程各自返回一次fork()一下干的几件事:
给P2分配Text段, Data段, Heap段, Stack段的虚拟地址,都指向P1中相应的物理地址P2的Text段是铁定和P1共享同一个物理地址了, 剩下的Data,Heap,Stack待定如果one of them 改变了这三个段的内容, 就把原来的数据复制一份给P2, 这样P2就有了相应的新的物理地址 //创建任意多个进程:子进程干活,父进程创建一个爹一堆儿子 int i=0; for(i=0;i<10;i++){ //创建10个进程, 只有parent在执行for()因为child在每次循环体内就exit()了 pid_t pid=fork(); if(-1==pid) perror("fork"),exit(-1); if(0==pid){ … exit(0); //终止子进程, 自然也就跳出了循环,防止再fork() } } #include<unistd.h> #include<stdlib.h> pid_t pid=fork(); if(-1==pid) perror(“fork”),exit(-1); if(0==pid){ //child process exit(0); } int main(){ pid_t pid=fork(); if(-1==pid) perror("fork"),exit(-1); printf("pid=%d\n",pid); if(0==pid){ printf("I'm child,my PID:%d,my parent's PID:%d\n",getpid(),getppid()); sleep(3); printf("I'm child,my PID:%d,my parent's PID:%d\n",getpid(),getppid()); }else{ sleep(1); printf("I'm parent,my PID:%d, my child's PID:%d\n",getpid(),pid); } return 0; } $./a.out pid=2915 pid=0 I'm child, my PID:2915, my parent's PID:2914 I'm parent,my PID:2914, my child's PID:2915 I'm child, my PID:2915, my parent's PID:1 #一个Orphan #卡在这, 因为两个进程抢一个终端,不是死循环,直接[ENTER]就行ATTENTION: vfork()主要与exec family搭配使用, 主要用语子进程执行与父进程完全不同代码段的场合中, 其中vfork()专门用于创建进程, exec family 专门用于跳转执行 , fork()虽然也可以和exec family 搭配使用, 但是fork()会复制父进程的内存空间, 复制完了又跳出去, 没什么意义, 效率不如(vfork(), exec family)
#include<unistd.h> #include<sys/types.h> if(0==pid){ int res=execl("./proc","proc",NULL); //"ls"就是执行方式, 以字符串的形式传进来, “proc”也是 if(-1==res) perror("execl"),_exit(-1); //ATTENTION,vfork用_exit() }退出状态exit status是我们传入到exit(),_exit(),_Exit()函数的参数。进程正常终止的情况下,内核将退出状态转变为终止状态以供父进程使用wait(),waitpid()等函数获取。终止状态termination status除了上述正常终止进程的情况外,还包括异常终止的情况,如果进程异常终止,那么内核也会用一个指示其异常终止原因的终止状态来表示进程,当然,这种终止状态也可以由父进程的wait(),waitpid()进程捕获。
Orphan Process:一个parent退出,而它的一个或多个child还在运行,那么这些child将成为orphan。将被init(PID==1)收养,并由init对它们完成状态收集工作。init会循环地wait()直到这些child完成了他们的工作. 即当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。
Zombie Process: 一个使用fork()创建的child,如果child退出,而parent并没有调用wait/waitpid获取child的状态信息,那么child的process descriptor、PID和PCB等资源仍然保存在系统中。此时的child就变成了zombie。因为系统的PID总数是有限的, parent不断的创建child而不去wait,系统早晚会被拖垮.
总结:
Orphan/Zombie都是因为在parent中没有wait掉child, 不同之处是orphan的parent已经没了, 由init来接管了,而zombie有个缺德的parent, 不wait还不撒手,拖累了系统$ps 一下Zombie的进程状态是’Z’Note:
运行结果a.txt两个进程没有覆盖=>父子进程使用的读写位置信息是同一份=>文件表是同一份=>但是两个是不同的fd, 所以fork()创建子进程也会复制一个文件描述符总表正是因为使用读写一次 offset会向后移, 所以没有覆盖, 因为后来的是使用前面留下的offset的位置, 所以使用的读写信息是一样的 /*-------------------------------------------- child终止时自动释放malloc() ----------------------------------------------*/ #include<unistd.h> #include<sys/types.h> #include<stdio.h> #include<stdlib.h> #define PI 3.141592657 int *ipdata=NULL; ///* void fa(){ free(ipdata); ipdata=NULL; } //*/ int main(){ pid_t pid=fork(); if(-1==pid) perror("fork"),exit(-1); if(0==pid){ printf("1"); printf("child starts\n"); ipdata=(int*)malloc(sizeof(int)); if(NULL==ipdata) printf("malloc fails\n"); // perror("malloc"),exit(-1); //??? // *ipdata=data; int res=atexit(fa); if(0!=res){ printf("atexit fails\n"); exit(EXIT_FAILURE); } printf("Please input a radius:"); scanf("%d",ipdata); printf("primeter is:%lf\n",2*PI*(*ipdata)); exit(EXIT_SUCCESS); } printf("parent starts\n"); int stat=0; pid=wait(&stat); if(WIFEXITED(stat)) printf("child has terminated,its status:%d\n",WEXITSTATUS(stat)); return 0; }Note:
用全局变量做桥梁atexit()里面的函数一定是int *(void)函数的形参列表变了也不行ATTENTION: vfork()的child虽然整个内存区都是和parent共享的, 但是变量的作用域还是在啊, 所以你跨函数使用变量肯定要传参的啊 /*-------------------------------------------- on_exit.c, child终止时自动释放malloc() ----------------------------------------------*/ #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<sys/wait.h> #include<stdio.h> #include<stdlib.h> #include<signal.h> void fa(int status,void* pv){ printf("obtained status=%d\n",status); free(pv); pv=NULL; } int main(){ //创建子进程,使用fork() pid_t pid=fork(); if(-1==pid){ printf("parent starts%d\n",pid); } if(0==pid){ printf("child starts%d\n",getpid()); int *pi=(int*)malloc(sizeof(int)); if(NULL==pi) printf("malloc error"),exit(-1); //use on_exit()register function if(0!=on_exit(fa,pi)) perror("on_exit"),exit(-1); printf("please input a radius(int)\n"); scanf("%d",pi); printf("the primeter is:%lf\n",2*3.14*(*pi)); //terminate child and free dynamic memory automatically exit(100); } //父进程等待子进程终止, 获取退出状态 int status=0; int res=waitpid(pid,&status,0); if(-1==res) perror("waitpid"),exit(-1); if(WIFEXITED(status)) printf("status of child:%d\n",WEXITSTATUS(status)); return 0;} 转自www.cnblogs.com/xiaojiang1025/p/5934317.html