fork与vfork的区别
(1)fork子进程拷贝父进程的数据段,vfork子进程与父进程共享数据段。
(2)fork父、子进程的执行次序不确定,vfork子进程先运行,父进程后运行。
(3)vfork有限制,子进程必须立刻执行_exit或者exec函数。
进程终止的方式
正常退出
从main函数返回
调用exit
调用_exit或_Exit
最后一个线程从启动进程返回
最后一个线程调用pthread_exit
异常退出
调用abort 产生SIGABOUT信号
接受到信号终止 例如:ctrl+c SIGINT
最后一个线程对取消请求做出响应
exec函数族
#include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg,..., char * const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[],char *const envp[]);
#include<stdio.h> #include<stdlib.h> #include<unistd.h> int main() { printf("pid is %d\n",getpid()); char *env[]={"1111","2222",NULL}; execle("./exec", NULL, env); return 0; } #include<stdio.h> #include<unistd.h> #include<stdlib.h> extern char ** environ; int main(int arg,char *argc[]) {int i; printf("exec process is running\n"); printf("pid is %d\n",getpid()); for(i=0;environ[i]!=NULL;i++) {printf("%s\n",environ[i]); } return 0; }
进程被完全替换后,pid并不会发生变化。
如果envp环境参数列表不填写,则替换程序会使用默认环境参数列表。
如果envp环境参数列表填写,则替换程序会使用自定义环境参数列表。
wait/waitpid
当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。父进程查询子进程的退出状态可以用wait/waitpid函数
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options); /*RETURN VALUE wait(): on success, returns the process ID of the terminated child; on error, -1 is returned. waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) speci‐fied by pid exist, but have not yet changed state, then 0 is returned.On error, -1 is returned.*/
#include<stdio.h> #include<stdlib.h> #include<sys/wait.h> #include<unistd.h> int main() { pid_t pid; int status; pid=fork(); if(pid>0) { printf("child process is running\n"); printf("pid is %d\n",getpid()); } else { waitpid(pid,&status,0); printf("parent process is runnning\n"); printf("pid is %d\n",getpid()); } return 0; }
僵尸进程
当一个子进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行或者父进程调用了wait才告终止。进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵尸进程”,为了避免僵尸进程,可以通过调用wait或者waitpid函数查询子进程退出状态。
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/wait.h> void exitstatus(int status) { if ( WIFEXITED(status) ) { printf("进程正常退出 退出状态码为: %d \n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("进程非正常退出 信号状态码为: %d \n", WTERMSIG(status) ); } else if ( WIFSTOPPED(status)) { printf("进程停止 信号状态码为:%d \n", WSTOPSIG(status) ); } } int main(int argc, char *argv[]) { int status; pid_t pid; pid = fork(); if (pid == 0) { sleep(3); printf("this is child\n"); exit(7); } if(wait(&status)==pid) { exitstatus(status); } pid = fork(); if (pid == 0) { sleep(3); printf("this is child\n"); abort(); } if(wait(&status)==pid) { exitstatus(status); } pid = fork(); if (pid == 0) { sleep(3); printf("this is child\n"); exit(0); } if(wait(&status)==pid) { exitstatus(status); } return 0; }