创建进程
fork
fork是一个系统调用函数,用来创建子进程,通过多个执行流完成任务。子进程和父进程共用一份代码,子进程数据使用写时拷贝,即子进程数据在创建的时候和父进程相同,但是当要修改数据的时候,子进程数据会再复制一份数据。
函数无参,返回值pid_t是用有符号整形封装的。
函数返回值,如果创建成功,父进程就返回子进程的pid,子进程返回0,如果创建失败就返回-1
循环创建多个进程
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4
5 void run()
6 {
7 while(1)
8 {
9 printf("child pid:%d\n",getpid());
10 sleep(1);
11 }
12 }
13
14 int main()
15 {
16 pid_t id;
17 int i;
18 for(i = 0; i < 5; i++)
19 {
20 id = fork();
21 if(id == 0)
22 {
23 run();
24 exit(0);
25 }
26 }
27 sleep(1000);
28 return 0;
29 }
终止进程
进程终止有三种情况:
1.结果正确,返回
2.结果错误,返回
3.程序异常
进程运行结束返回值可以使用return,exit(),_exit()。程序异常一般是外部发给程序一个信号,程序异常终止
正常终止
return,exit(),_exit()三者的区别是什么?
return和exit()
在main函数中,return和exit都可以让进程结束;在一般函数中,return只是让函数返回,继续运行,而exit会直接终止进程
exit()和_exit()
_exit是系统调用接口,直接终止程序;exit调用了_exit,并且会先刷新缓冲区做一些清理工作。
因为printf内容不加\n不会刷新缓冲区,不会打印出来
异常终止
写一个死循环让程序一直运行
这里向程序发送Floating Point exception异常信号
程序收到信号后,异常终止
进程等待
当子进程还没有退出,父进程就要退出时,如果父进程不等待子进程直接退出,就会让子进程变为僵尸进程造成内存泄漏。因此我们需要用进程等待的方式获取子进程的运行状态以及退出码。
介绍两个系统调用接口:
wait和waitpid
waitpid的功能包含了wait,我们先说waitpid
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
pid表示子进程的pid:
-1表示等待任何子进程,和wait一样后面讲
>0表示等待子进程为pid的进程
status是一个输出型参数:
int有32bit,前16位是有效位。前七位是终止信号,如果程序异常终止就会将信号保存到这里;第八位是core dump标志;8-16位是退出码
WIFEXITED
(status)可以判断子进程是否正常结束
- 如果子进程正常结束(通过
exit
调用或从主函数返回),WIFEXITED
返回非零值(真) - 如果子进程是由于其他原因结束(如信号),则返回零值(假)
WEXITSTATUS(status)
可以用来获取子进程传递给 exit()
的实际退出值
option是用来修改waitpid行为的选项
没传参时默认为阻塞轮询,即父进程必须等待子进程结束才继续执行
传 WNOHANG 表示非阻塞轮询,父进程获取子进程状态后不论子进程是否结束都会先执行自己的代码。如果子进程结束返回子进程pid;如果未结束返回0
返回值
>0表示子进程正常结束,返回子进程pid
0 表示子进程还未结束
<0表示子进程异常结束
阻塞轮询:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <stdlib.h>
6
7 int main()
8 {
9 for(int i = 0; i < 5; i++)
10 {
11 pid_t id = fork();
12 if(id == 0)
13 {
14 printf("child pid:%d\n", getpid());
15 sleep(1);
16 exit(0);
17 }
18 }
19
20 sleep(5);
21
22 int status = 0;
23 for(int i = 0; i < 5; i++)
24 {
25 pid_t ret = waitpid(-1, &status, 0);
26 if(ret > 0)
27 {
28 printf("wait success pid:%d\n", ret);
29 sleep(1);
30 }
31 }
32 return 0;
33 sleep(5);
34 }
运行结果
运行过程的进程监视
阻塞轮询:
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <stdlib.h>
6 #include <errno.h>
7 #include <string.h>
8
9 int main()
10 {
11 //非阻塞轮询
12
13 pid_t id = fork();
14 if(id == 0)
15 {
16 //child
17 printf("child pid:%d, ppid:%d\n", getpid(), getppid());
18 //测试异常
19 //int* p = NULL;
20 //*p = 1;
21 sleep(10);
22 exit(1);
23 }
24 else if(id > 0)
25 {
26 int status;
27 //father
28 while(1)
29 {
30 pid_t ret = waitpid(id, &status,WNOHANG);
31 if(ret == id)
32 {
33 if(WIFEXITED(status))
34 {
35 //正常结束
36 printf("wait success, exit code:%d\n", WEXITSTATUS(status));
37 break;
38 }
39 }
40 else if(ret < 0)
41 {
42 //异常
43 printf("wait fail,%s\n",strerror(status & 0x7f));
44 break;
45 }
46 else
47 {
48 //子进程还在执行
49 printf("child running,wait a minute\n");
50 sleep(1);
51 }
52 }
53 }
正常结束
异常结束