Day28、进程的管理(创建、退出)、子进程
来源:互联网 发布:21天学通c语言视频 编辑:程序博客网 时间:2024/06/05 08:28
一、进程的管理
1、什么是进程?
进程是程序运行的一个实例。
PCB(进程控制块)
pid:进程号
2、Linux进程的组织管理方式
在linux操作系统中,所有的用户进程组成了一棵树,进程和进程之间的关系是父子关系,或兄弟关系。
tarena@tarena-virtual-machine:~$ pstree
init─┬─NetworkManager─┬─dhclient
│ ├─dnsmasq
│ └─2*[{NetworkManager}]
├─accounts-daemon───{accounts-daemon}
├─acpid
├─atd
├─avahi-daemon───avahi-daemon
init 1号进程 是进程树的树根
pstree (命令) :列出所有用户进程
ps –aux (命令):查看当前进程的详细信息
3、怎么获取进程的pid ?
getpid (2)系统调用:系统调用是用内核来提供服务
#include<sys/types.h>
#include<unistd.h>
pid_tgetpid(void);
pid_tgetppid(void);
功能:获取进程的进程号
参数:
返回值:
举例:pid.c
1#include<stdio.h>
2#include<sys/types.h>
3#include<sys/unistd.h>
4int main(void){
5 pid_t pid;
6 pid=getpid();
7 printf("pid=%d\n",pid);
8 getchar();
9 return 0;
10 }
tarena@tarena-virtual-machine:~$ gcc pid.c
tarena@tarena-virtual-machine:~$ ./a.out
pid=3154
tarena@tarena-virtual-machine:~$ ps -aux
tarena@tarena-virtual-machine:~$ gcc pid.c-E -o getpid.i (查看typedefine pid_t的类型)
tarena@tarena-virtual-machine:~$ pstree
├─gnome-terminal─┬─bash───pstree
│ ├─bash───a.out
bash是pstree和a.out的父进程
4、创建一个子进程
fork (2)
#include<unistd.h>
pid_tfork(void);
功能:创建一个子进程
返回值:
在父进程中,子进程的pid被返回
在子进程中,0被返回
-1代表fork系统调用失败。errno被设置
注意:当fork调用结束时,内核就已经有两个进程(父与子),两个PCB
两个进程都运行这个程序往下走,先执行父进程还是子进程不一定
fork 执行后,父进程和子进程执行同一段代码
子进程还是父进程先执行是异步的。(谁先谁后执行不确定,系统调用决定)
举例:fork.c
1 #include<stdio.h>
2#include<unistd.h>
3int main(){
4 pid_t pid;
5 pid=fork();//此时,已经有两个进程
6 if(pid<0){ //创建子进程失败
7 perror("fork");
8 return 1;
9 }
10 if(pid= =0){// 子进程创建成功
11 printf("pid=%d\n",getpid());//打印子进程的pid
12 }
13 else{//如果不加else父进程和子进程都执行下一条语句,加上后只有父进程执行
14 printf("mypid=%d\n",getpid());//父进程的pid
15 }
16 return 0;
17 }
tarena@tarena-virtual-machine:~$ ./a.out
mypid=3227
pid=3228
总结:当fork成功调用完毕的时候,子进程复制了一份父进程的PCB,这时父子进程只有pid不同,每个进程有自己的一份PCB
(创建出子进程后,父子进程都运行以下的程序)
1#include<stdio.h>
2#include<unistd.h>
3int main(){
4 pid_t pid;
5 pid=fork();//此时,已经有两个进程
6 if(pid<0){ //创建子进程失败
7 perror("fork");
8 return 1;
9 }
10 if(pid==0){// 子进程创建成功
11 printf("pid=%d\n",getpid());//打印子进程
12 }
13 else{
14 printf("mypid=%d\n",getpid());//父进程
15 }
16 getchar();
17 return 0;
18 }
tarena@tarena-virtual-machine:~$ ./a.out
mypid=3235
pid=3236
tarena@tarena-virtual-machine:~$ ps –aux
tarena 3235 0.0 0.0 2008 284 pts/4 S+ 02:26 0:00 ./a.out
tarena 3236 0.0 0.0 2008 60 pts/4 S+ 02:26 0:00 ./a.out
tarena 3238 0.0 0.2 6368 1172 pts/3 R+ 02:27 0:00 ps –aux
tarena@tarena-virtual-machine:~$ pstree
├─gnome-terminal─┬─bash───pstree
│ ├─bash───a.out───a.out
练习:用进程创建子进程,在子进程再创建子进程
1#include<stdio.h>
2#include<unistd.h>
3int main(){
4 pid_t pid1,pid2,pid3;
5 pid1=fork();
6 if(pid1<0){
7 perror("fork");
8 return 1;
9 }
10 if(pid1==0){
11 printf("pid1=%d\n",getpid());//打印子进程
12 pid2=fork();
13 if(pid2<0){
14 perror("fork");
15 return 1;
16 }
17 if(pid2= =0){
18 printf("pid2=%d\n",getpid());//打印子进程
19 pid3=fork();
20 if(pid3<0){
21 perror("fork");
22 return 1;
23 }
24 if(pid3= =0){
25 printf("pid3=%d\n",getpid());//打印子进程
26 }
27 }
28 }
29 else{
30 printf("父进程pid=%d\n",getpid());
31 }
32 getchar();
33 return 0;
34 }
tarena@tarena-virtual-machine:~$ ./a.out
父进程pid=3273
pid1=3274
pid2=3275
pid3=3276
tarena@tarena-virtual-machine:~$ pstree
├─gnome-terminal─┬─bash───pstree
│ ├─bash───a.out───a.out───a.out───a.out
5、进程的同步:(同步指的是有顺序,一个进程执行完另一个执行)
wait/waitpid (2)系统调用
wait是阻塞的,只能等待一个子进程
waitpid是非阻塞的,能等待所有子进程
wait(2)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:等待子进程的结束,并获得子进程的状态信息
参数:
status:子进程的退出状态 是值传递(传个地址过去,带值回来)
WIFEXITED(status):用来判断子进程是否正常退出,如果正常退出返回turn。
WEXITSTATUS(status):用来获取到子进程的退出状态码
WIFSIGNALED(status):用来 子进程是不是被信号打断所中断
WTERMSIG(status):获取子进程被信号打断的信号的编号
返回值:-1代表错误,若正确,带回子进程的进程号
举例:wait.c
1#include<stdio.h>
2#include<sys/wait.h>
3#include<unistd.h>
4int main(){
5 pid_t pid;
6 int status;
7 pid=fork();
8 if(pid<0){
9 perror("fork");
10 return 1;
11 }
12 if(pid= =0){
13 printf("子进程pid=%d\n",getpid());//子进程
14 }
15 else{
16 wait(&status);//等待子进程的结束
17 printf("父进程pid=%d\n",getpid());
18 }
19 getchar();
20 return 0;
21 }
tarena@tarena-virtual-machine:~$ ./a.out
子进程pid=3321
(回车)
父进程pid=3320
修改wait1.c 扩展功能,获得子进程的状态信息
1#include<stdio.h>
2#include<sys/wait.h>
3#include<unistd.h>
4#include<stdlib.h>
5int main(){
6 pid_t pid;
7 int status;
8 pid=fork();
9 if(pid<0){
10 perror("fork");
11 return 1;
12 }
13 if(pid==0){
14 printf("子进程pid=%d\n",getpid());
15 exit(1);
16 }
17 else{
18 wait(&status);
19 if(WIFEXITED(status)){//如果正常退出,返回真
20 printf("status=%d\n",WEXITSTATUS(status));
21 }
22 printf("父进程pid=%d\n",getpid());
23 exit(0);
24 }
25 /* getchar();
26 return 0;*/
27 }
waitpid(2)
pid_t waitpid(pid_t pid, int *status, intoptions);
功能:回收子进程
参数:
pid:指定回收的子进程的子进程号
-1:所有的子进程
0:和父进程同组的子进程
>0:pid指定的子进程
<-1:等待组id等于pid的绝对值的子进程
status:同wait的status参数
(
WIFEXITED(status):用来判断子进程是否正常退出,如果正常退出返回turn。
WEXITSTATUS(status):用来获取到子进程的退出状态码
WIFSIGNALED(status):用来 子进程是不是被信号打断所中断
WTERMSIG(status):获取子进程被信号打断的信号的编号
)
options:
0:阻塞
WNOHANG:非阻塞
返回值:若失败,返回-1
举例:waitpid.c (非阻塞)
1#include<stdio.h>
2#include<sys/wait.h>
3#include<unistd.h>
4#include<stdlib.h>
5int main(){
6 pid_t pid;
7 int status;
8 pid=fork();
9 if(pid<0){
10 perror("fork");
11 return 1;
12 }
13 if(pid==0){
14 printf("子进程pid=%d\n",getpid());
15 sleep(30);
16 exit(1);
17 }
18 else{
19 pid_t r_pid=waitpid(-1,&status,WNOHANG/*非阻塞*/);//等待结束再执行
20 if(r_pid==-1){
21 perror("waitpid");
22 return 3;
23 }
24 //如果正常退出,返回真。exit(3)
25 if(WIFEXITED(status)){
26 printf("status=%d\n",WEXITSTATUS(status));
27 }
28 printf("父进程pid=%d\n",getpid());
29 exit(0);
30 }
31 /* getchar();
32 return 0;*/
33 }
tarena@tarena-virtual-machine:~/day28$./a.out
父进程pid=3232
子进程pid=3233
若改成
20 pid_tr_pid=waitpid(-1,&status,0 /* 阻塞*/);//等待结束再执行
tarena@tarena-virtual-machine:~/day28$ ./a.out
子进程pid=3245
在等待状态。 以上两个代码对比阻塞和非阻塞的区别
6、进程的退出: exit on_exit at_exit _exit
exit:进程退出
return:只是函数的返回。如果在main函数中,return相当于exit退出
#include <stdlib.h>
void exit(int status);
0377 1111,1111 一个字节 0~255 只要后八位
atexit(3)
#include <stdlib.h>
int atexit(void (*function)(void));
参数:
void (*function)(void)
参数的名字:function
参数的类型是 :*
回调函数:函数里有一个形参,这个形参又是一个函数的入口地址。在这个参数寄存的那个函数里,可以回调其传进来的函数
回调函数
可以当做实际参数使用的函数叫做回调参数
将一个函数的地址作为实参传递给另一个调用函数
举例:
1#include<stdio.h>
2#include<stdlib.h>
3//回调函数的定义
4 void func(void){
5 printf("this is atest\n");
6 }
7int main(void){
8 //向exit函数注册atexit函数
9 atexit(func);
10 exit(0);
11 }
on_exit(3)
#include <stdlib.h>
int on_exit(void (*function)(int , void *),void *arg);
1#include <stdio.h>
2#include <stdlib.h>
3//回调函数的定义
4void func(void)
5 {
6 printf("this is apig\n");
7 }
8
9void onfun(int val,void *p)
10 {
11 char *buf=(char *)p;
12 printf("val=%d\tbuf=%s\n",val,buf);
13 }
14
15int main(void)
16 {
17 char *str="tang";
18 //向exit函数注册atexit函数
19 atexit(func);
20 on_exit(onfun,str);
21 exit(3);
22 }
程序执行到exit时会回调atxit和on_exit
tarena@tarena-virtual-machine:~/day28$./a.out
val=3 buf=tang
this is a pig
_exit (2)
#include <unistd.h>
void _exit(int status);
exit (3)调用了_exit(2) 系统调用 调用了 库函数
举例说明:
fopen(3)(FILE *)-----àOPEN(2)(fd) ----àclose(fd)---àfclose(3)
7、孤儿进程和僵尸进程?
什么是孤儿进程?
父进程早于子进程结束,这个子进程就叫孤儿进程
在这种情况下,子进程的父进程由init进程代理(孤儿院)
举例:
1#include<stdio.h>
2#include<sys/wait.h>
3#include<unistd.h>
4#include<stdlib.h>
5int main(){
6 pid_t pid;
7 int status;
8 pid=fork();
9 if(pid<0){
10 perror("fork");
11 return 1;
12 }
13 if(pid==0){
14 printf("子进程pid=%d\n",getpid());
15 sleep(20);
16 }
17 else{
18 printf("父进程pid=%d\n",getpid());
19 exit(0);
20 }
21 /* getchar();
22 return 0;*/
23 }
tarena@tarena-virtual-machine:~/day28$./a.out
父进程pid=2895
子进程pid=2896
tarena@tarena-virtual-machine:~/day28$pstree
init─┬─NetworkManager─┬─dhclient
│ ├─dnsmasq
│ └─2*[{NetworkManager}]
├─a.out
僵尸进程:zombies
子进程结束的时候,父进程需要调用wait来获取子进程的退出状态,并且回收一些信息。
如果子进程结束了,父进程没有调用wait来及时地清理信息,在这个瞬间,子进程的状态就是僵尸状态。
1#include<stdio.h>
2#include<sys/wait.h>
3#include<unistd.h>
4#include<stdlib.h>
5int main(){
6 pid_t pid;
7 int status;
8 pid=fork();
9 if(pid<0){
10 perror("fork");
11 return 1;
12 }
13 if(pid==0){
14 printf("子进程pid=%d\n",getpid());
15 exit(1);
16 }
17 else{
18 sleep(30);
19 printf("父进程pid=%d\n",getpid());
20 wait(NULL);
21 }
22 /* getchar();
23 return 0;*/
24 }
tarena@tarena-virtual-machine:~/day28$ ./a.out
子进程pid=2922
父进程pid=2921
tarena@tarena-virtual-machine:~$ ps –aux
tarena 2992 0.0 0.0 2000 284 pts/0 S+ 06:46 0:00 ./a.out
tarena 2993 0.0 0.0 0 0 pts/0 Z+ 06:46 0:00 [a.o] <defunct>
判断大端小端:
1 #include<stdio.h>
2 int main(void){
3 short var_s=0x0001; // 00000001
4 char *p=(char *)&var_s; p指向短整型的一个字节
5 if(*p){
6 printf("小端\n");
7 }
8 else{
9 printf("大端\n");
10 }
11 }
小端
计算机一般是小端,低字节放在低地址 左边高地址,右边是低地址 0000001
网络传输一般是大端,低字节放在高地址,信号按序列发送
- Day28、进程的管理(创建、退出)、子进程
- vb6创建子进程并等待子进程的退出。
- 退出子进程的办法
- 子进程的创建
- 子进程的创建
- 进程的创建以及退出
- 进程的创建以及退出
- 进程的创建、运行、退出
- 进程的创建,等待,退出,
- Linux 进程--父进程查询子进程的退出状态
- Linux 进程--父进程查询子进程的退出状态
- linux 进程的管理、子进程创建、进程资源的回收
- linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid
- 创建守护进程:先建立守护进程,在守护进程建立一个子进程,该子进程暂停10s,然后退出,并由该守护进程收集子进程退出的消息。子进程,守护进程的退出消息都在/var/log/message中输出,子进程退
- 创建进程和退出进程
- Linux并发(子进程退出状态的处理)
- Linux并发(子进程退出状态的处理)
- 解决子进程自动退出的问题
- 一个EXT3的文件分区,当使用touch test.file命令创建一个新文件时报错,报错的信息是提示磁盘已满
- 斐波那契数列的两种表达方式
- 兼容
- 京东笔试编程题:进制均值(C++)
- 笔试总结
- Day28、进程的管理(创建、退出)、子进程
- this与super有什么区别
- 2016ACM暑假集训总结
- Mysql学习笔记(一)
- sap模板
- [BZOJ3729]Gty的游戏/[JZOJ4759]石子游戏
- 小球随机出现在屏幕
- electron
- 跑马灯demo