今天:进程结束 -fork() /exit退出进程/wait()父进程等待子进程/vfork()Unix/Linux 信号
break是用来退循环,return退函数,exit()退进程
程序员退出进程的方式:
1.正常退出
a.在主函数中执行了return语句(特殊的,因为只对主函数有效)
b._exit()或_Exit()函数退出进程(立即退出)
c. exit()退出进行(通用方式)
d.最后一个线程结束
2.非正常退出
a.被信号干掉了,比如:ctrl+cb.最后一个线程被取消
exit()/_exit()/_Exit()_exit(int) /_EXIT(int)这两个在底层是一样的,_Exit()调用了_exit()
exit()函数会退出进程,但不一定是马上退出,允许通过atexit()函数注册一些其他的函数,在退出前会先执行注册过的函数。
_exit()函数会立即退出,退出只做三件事:
1.关闭文件描述符
2.让所有的子进程变成孤儿进程
3.发退出信号给父进程如果没有特殊需求,退出进程用exit()即可。
wait()和waitpid()
wait()和waitpid()可以让父进程等待子进程的结束,可以取得子进程结束的方式(正常退出还是非正常退出)和退出码
wait()必须等待任意一个子进程的结束,只要有子进程结束,那么wait()就返回,如果没有子进程结束,父进程继续等待。waitpid()可以等待多种方式的子进程,也可以一个都不等待,因此更灵活。
wait()和waitpid()能回收僵尸子进程的资源。
pid_t wait(int* status)
功能:等待任意一个子进程的结束,并取得退出状态和退出码参数:
status是传出参数,返回子进程的退出状态和退出码返回值:返回结束子进程的PID
宏函数被用于判断子进程的退出状态和获取退出码WIFEXITED(status) 判断是否正常退出WEXITSTATUS(status)获取退出码(只有正常退出才有效)
5 int main()
6{
7 pid_t pid = fork();
8 if(pid==0){//子进程分支
9 sleep(2);
10 printf("子进程%d开始运行\n",getpid());
11 sleep(2);
12 printf("子进程%d结束\n",getpid());
13 exit(10);
14 }
15 int status;
16 pid_t wpid= wait(&status);
17 if(WIFEXITED(status))
18 {
19 printf("子进程%d结束,退出码%d\n",wpid,WEXITSTATUS(status));
20 }
21 printf("父进程结束\n");
22
运行结果:
子进程14587开始运行
子进程14587结束
子进程14587结束,退出码10
父进程结束
pid_t waitpid(pid_t pid,int* status,int options)
功能:等待子进程的结束,但比wait()更灵活(可以不等)
第一个参数:pid是等待哪个/哪些子进程,包括:
-1 等待任意一个子进程的结束
>0 等待特定的一个子进程(进程ID=pid)
0 等待和父进程一个进程组的子进程(本组)
<-1等待指定进程组的子进程(进程组ID=|pid|)
第二个参数:status和wait()中的一样
第三个参数:option可以设置等待或是不等待,默认0为等待,宏WNOHANG可以代表不等待。
返回:有子进程结束返回结束子进程的PID,如果不等待并且没有子进程结束返回0,失败返回-1。
int main()
7 {
8 pid_t pid1,pid2;//一父二子需要判断
9 pid1 = fork();
10
11 if(pid1>0)pid2 = fork();
12 if(pid1==0){//进程1
13 sleep(1);
14 printf("子进程-%d结束\n",getpid());
15 exit(20);
16 }
17 if(pid2==0) {
18 sleep(3);
19 printf("子进程-%d结束\n",getpid());
20 exit(20);
21 }
22 int status;
23 pid_t wpid = waitpid(pid1,&status,0);
24 if(WIFEXITED(status))
25 {
26 printf("子线程%d,退出码%d\n",wpid,WEXITSTATUS(status));
27 }
28 }
vfork() +execl()创建子进程
fork()函数从语法上和fork()没有任何区别,区别在于fork()不会复制父进程的任何资源。子进程会占用父进程的资源继续运行,而父进程会阻塞,停止运行。父进程的阻塞有两种方法可以解除
1.子进程运行结束,把资源还给父进程
2.子进程调用了execl(),启动了一个全新的程序,也把原来的资源还给父进程(并行的方式)。
第二种方法更有意义更常用,第一种方法没有实际意义。
vfork()会创建一个新的子进程,可以确保子进程先运行。
vfork()创建的子进程必须用exit()退出,return语句退出会有问题。
vford()函数能创建子进程,但是不能提供代码和数据,execl()函数不能创建子进程,但可以提供进程运行的代码和数据。
execl()函数不会创建新的进程,进程PID不变,用一个新的程序替换掉当前进程执行的程序。
int execl(char* path,char* cmd,...)
功能:启动一个全新的程序,当前程序将被替换,但不会建立新进程
参数:path就是新程序的路径,包括文件名,不能出错
cmd就是运行程序的命令,比如:a.out
...可以包括命令的参数/命令的选项,最后以NULL结束
返回:成功则启动新程序,没有任何返回值
失败就无法启动新程序,返回-1
关于进程必须会写代码:
fork()
vfork()和execl()
网友评论