进程的退出(_exit,exit,return)
exit和_exit:两者都可以在任意位置,退出进程,并且返回退出码。
区别:exit是C语言库函数,其不仅仅会进行程序退出,还会进行某些资源的的清理,如刷新缓冲区,_exit是系统调用,就只是进程退出,不会做资源的清理。
示例代码:下面就不会打印出本该打印的字符串,原因就是直接被进程直接退出,且没有清理后续资源,那部分资源也就被清理掉了。
//由此可以看见,缓冲区不在系统层面,否则来自系统层面的_exit是可以进行清理的。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
19 int main()
20 {
21
23 printf("pid is %d,ppid is%d ---",getpid(),getppid());
sleep(2);
23 _exit(101);
24 //exit(100);//换成exit即可看见打印内容
25 return 32;//you can see the exit code by the "echo $? following the process exited"
26 }
进程的等待
为什么要有:
1.处理子进程的僵尸状态—这是必须的
2.获取子进程退出信息,以了解子进程的完成情况
wait,waitpid:两个都用于进程等待
下面是通过man查看的手册。
参数就是首先不同,wait作用是等待任意一个进程,等到就返回,且是阻塞形等待。
两者都有**status:**下面会详细介绍,其真正的作用(通过整形指针给整形赋值)是得到返回信息,所以如果你传空指针,意味着就不在意子进程的返回情况。
pid:
可以通过给pid传参数,选择等待任意一个进程,如果传值给-1,其就表示可以等待任意一个进程,option再传0的话,和wait效果就一样了。
**options:**传0或者1(默认的是0,也就是阻塞等待)来选择等待的类型,轮询等待还是阻塞形式等待
返回值意思也是同样的,成功返回等到的子进程的pid,失败的话返回小于0的数。
status
**statu的构成:一个32位的整数,但实际传过去用的时候,只用了低16位的数字而不是全用。 **
在这低16位的使用之中:
高八位是用于表示退出码。
低7位表示的是退出信号(表示代码执行情况)
WTERMSIG(status) 可以获取低7位的信号码
WEXITSTATUS 获取退出码·
上面我们就能看见,这是一个整形指针。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6
7 void Worker()
8 {
9 for(int cnt = 0;cnt<5;cnt++)
10 {
11 //int a = 1;
W> 12 //a/=0;//测试信号码
13 printf(" child process,pid is %d ,ppid is %d \n",getpid(),getppid());
14 sleep(1);
15 }
16 }
17 int main()
18 {
19 pid_t pid = fork();
20 if(pid==0)
21 {
22 //child process
23 Worker();
24 exit(0);
25 }
26 else{
27 sleep(10);
28 // pid_t rid = wait(NULL);
29 int status = 0;
30 pid_t rid = waitpid(pid,&status,0);
31 printf("%d",status);
32 if(rid == pid)
33 {
34 printf("wait success ,pid : %d,exitsig:%d,exit code:%d",getpid(),status&0x7F,(status>>8)&0xFF);
35 }
36 }
37 return 0;
38 }
上面注释部分如果取消,下面就可以是答案,我们通过这点可以发现,信号码出现错误了,退出码其实就没什么价值了。
子进程被杀掉,也算是异常(按我们日常使用的理解,突然关闭某个程序,确实应该就算异常)
阻塞形等待:下面就是示例,在等待的时候,父进程会挂起等着子进程结束。
下面代码运行时,可以查看进程状况,即可发现,子进程的僵尸进程就被处理了。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6
7 void Worker()
8 {
9 for(int cnt = 0;cnt<5;cnt++)
10 {
11 printf(" child process,pid is %d ,ppid is %d \n",getpid(),getppid());
12 sleep(1);
13 }
14 }
15 int main()
16 {
17 pid_t pid = fork();
18 if(pid==0)
19 {
20 //child process
21 Worker();
22 exit(0);
23 }
24 else{
25 sleep(10);
26 pid_t rid = wait(NULL);//NULL表示不在乎子进程进行情况
27 if(rid == pid)
28 {
29 printf("wait success ,pid : %d\n",getpid());
30 }
31 }
32 return 0;
33 }
//下面是创建了十个子进程,用waitpid去回收。
从其结果来说,说明进程的执行情况是各不相同的,子进程先创建,不会就先执行完,其调度不是认为创建先后就决定的。
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6
W> 7 void Worker(int i)
8 {
9 for(int i = 0;i<2;i++)
10 {
11 printf("I am a child process,pid is %d,ppid is %d\n",getpid(),getppid());
12 sleep(1);
13 }
14 }
15
16 int main()
17 {
18 for(int i = 0;i<10;i++)
19 {
20 pid_t id = fork();
21 if(id==0)
22 {
23 //child
24 Worker(i);
25 exit(i);
26 }
27 }
28 for(int i = 0;i<10;i++)
29 {
30 int status;
31 pid_t rid = waitpid(-1,&status,0);//pid is always larger than 1, -1 is the wait child pr ocess can be anyone
32 if(rid>0)
33 {
34 printf("child process id:: %d<< success\n",status>>8);
35 }
36 }
37
38 return 0;
39 }
轮询式等待
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/wait.h>
5 #include <sys/types.h>
6
7 #define TASK_NUM 2
8
9 typedef void(*tskPtr)();
10
12 void download()
13 {
14 printf("this is a download\n");
15 }
16
17 void show()
18 {
19 printf("this is a show info \n");
20 }
21
22 void InitialTasks(tskPtr task[],int num)
23 {
24 for(int i = 0;i<num;i++) task[i] = NULL;
25 }
26
27 int AddTask(tskPtr task[],tskPtr t)
28 {
29 for(int i= 0;i<TASK_NUM;i++)
30 {
31 if(task[i]==NULL)
32 {
33 task[i] = t;
34 return 1;
35 }
36 }
37 return 1;
38 }
39
40 void executeTask(tskPtr task[],int num)
41 {
42 for(int i = 0;i<num;i++)
43 {
44 task[i]();
45 }
46 }
47
48 int main()
49 {
50 tskPtr task[TASK_NUM];
51 InitialTasks(task,TASK_NUM);
52 AddTask(task,download);
53 AddTask(task,show);
54
55 pid_t pid = fork();
56 if(pid==0)
57 {
58 int cnt=10;
59 while(--cnt)
60 {
61 sleep(1);
62 printf("I am child process ,pid is %d,time left is %d\n",getpid(),cnt);
63 }
64
65 exit(0);
66 }
67 else{
68 //father
69 pid_t rid;
70 while(1)
71 {
72 int status = 0;
73 rid = waitpid(pid,&status,1);
74 if(rid>0)
75 {
76 sleep(1);
77 printf("child process success,exit code: %d,exit signal:%d\n",(status>>8)&0xFF,status&0x7F);
78 break;
79 }
80 else if(rid==0)
81 {
82 sleep(1);
83 executeTask(task,TASK_NUM);
84 printf("wait child proceess ,father can do others\n");
85 }
86 else{
87 sleep(1);
88 printf("wait flase,rid id%d\n",rid);
89 break;
90 }
91 }
92 }
93 return 0;
94 }
观察可得,这种等待期间,是可以去父进程可以执行其他时间,只需要每隔一段时间来等待子进程就可以,而不是直接挂起等着子进程,同时子进程也可以执行一些任务。