在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
09-linux-day05(进程控制)
一、学习目标
1、了解进程相关的概念
2、掌握fork/getpid/getppid函数的使用
3、熟练掌握ps/kill命令的使用
4、熟练掌握execl/execlp函数的使用
5、说出什么是孤儿进程什么是僵尸进程
6、熟练掌握wait函数的使用
7、熟练掌握waitpid函数的使用
二、进程
1、进程和程序
什么是程序?编译好的二进制文件。
什么是进程?运行着的程序。
站在程序员的角度:运行一系列指令的过程。
站在操作系统角度:分配系统资源的基本单位。
区别:
程序占用磁盘,不占用系统资源。
进程占用系统资源。
一个程序对应多个进程,一个进程对应一个程序。
程序没有生命周期,进程有生命周期。
2、单道和多道程序设计
3、进程的状态转化
进程的状态切换
4、MMU 的作用
》MMU作用:1)虚拟内存和物理内存的映射;2)修改内存访问级别
用户空间映射到物理内存是独立的。
5、PCB的概念
Linux内核的进程控制块是task_struct结构体。
查找结构体:
> sudo grep -rn "struct task_struct {" /usr/
技巧:光标停留在{上,按%,可以到结构体的结尾。(400多行)
查看进程的资源上限:
>ulimit -a
6、获取环境变量
查看所有的环境变量:(写法:key=value,且等号两端不能有空格)
>env
常见的环境变量:
>echo $HOME
>echo $PATH
》getenv函数——获取环境变量
man 2 getenv
char *getenv(const char *name);
>touch getenv.c
>vi getenv.c
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 printf("homepath is [%s]\n", getenv("HOME"));
7 return 0;
8 }
>make
>./getenv
》setenv函数——设置环境变量的值
man 2 setenv
int setenv(const char *name, const char *value, int overwrite);
参数overwrite取值:1-覆盖原环境变量;0-不覆盖(该参数常用于设置新环境变量。)
一般配置(.bashrc)文件!(如:export key=val;)
》unsetenv函数——删除环境变量name的定义
man 2 unsetenv
int unsetenv(const char *name);
注意事项:name不存在仍返回0(成功),当name命名为“ABC=”时则会出错!
7、进程控制函数fork
>touch fork.c
>vi fork.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 printf("Begin ....\n");//此处缺少“\n”结果会不一样,这是由于printf有缓冲区机制,往屏幕上输出,会有行缓冲
7 pid_t pid = fork();
8 printf("End ....\n");
9 return 0;
10 }
>make
>./fork
(可以知道结束了两个进程。)
》getpid获得当前进程的PID和进程ID,,getppid——获得当前进程父进程的ID
man getpid
pid_t getpid(void);
pid_t getppid(void);
8、fork创建子进程
>vi fork.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7 printf("Begin ....\n");
8 pid_t pid = fork();
9 if(pid < 0){
10 perror("fork err");
11 exit(1);
12 }
13 if(pid == 0){
14 //子进程
15 printf("I am a child,pid = %d,ppid = %d\n",getpid(), getppid());
16 }
17 else if(pid > 0){
18 //父进程的逻辑
19 printf("childpid=%d,self=%d,ppid=%d\n",pid,getpid(),getppid());
20 sleep(1);//让父进程等待一段时间,在死去。
21 }
22
23 printf("End ....\n");
24 return 0;
25 }
>make
>./fork
9、进程控制的命令
>vi fork.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7 printf("Begin ....\n");
8 pid_t pid = fork();
9 if(pid < 0){
10 perror("fork err");
11 exit(1);
12 }
13 if(pid == 0){
14 //子进程
15 printf("I am a child,pid = %d,ppid = %d\n",getpid(), getppid());
16 while(1){
17 printf("I am a child\n");
18 sleep(1);
19 }
20 }
21 else if(pid > 0){
22 //父进程的逻辑
23 printf("childpid=%d,self=%d,ppid=%d\n",pid,getpid(),getppid());
24 while(1){
25 sleep(1);
26 }
27 }
28
29 printf("End ....\n");
30 return 0;
31 }
>make
>./fork
让子进程一直保持运行,打开另一个终端查看PPID和PID分析:
》ps aux——查看进程相关信息的指令
》ps ajx——可以查看更多进程相关的信息,从而追溯进程之间的血缘关系
可以看到PPID、PID,可以看出shell进程是所有进程的父亲,继续追溯,可以看到最终父进程是init
(init进程是所有进程的祖先!)
>kill -9 2890
>ps ajx
杀死了父进程,init成为子进程2891新的父亲。
>kill 2891
杀死子进程
》kill指令——给进程发送一个信号
kill -l 查看信号相关的信息
SIGKILL 9号信号
kill -9 pid——杀死进程
10、创建n个子进程
需求:让父进程创建n个子进程
>touch nfork.c
>vi nfork.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7 int n = 5;
8 int i = 0;
9 pid_t pid = 0;
10 for(i = 0; i < 5; i++){//父进程循环结束
11 pid = fork();
12 if(pid == 0){
13 //son
14 printf("I am child, pid=%d,ppid=%d\n",getpid(),getppid());
15 break;//子进程退出循环的接口
16 }
17 else if(pid > 0){
18 //father
19 printf("I am father, pid=%d,ppid=%d\n",getpid(),getppid());
20 }
21 }
22 while(1){
23 sleep(1);
24 }
25 return 0;
26 }
>gcc nfork.c
>./a.out
>ps aux | grep a.out |grep -v grep | wc -l
11、循环创建n个子进程控制顺序
》需求:精确控制各个子进程
>touch nfork1.c
>vi nfork1.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<stdlib.h>
4
5 int main()
6 {
7 int n = 5;
8 int i = 0;
9 pid_t pid = 0;
10 for(i = 0; i < 5; i++){//父进程循环结束
11 pid = fork();
12 if(pid == 0){
13 //son
14 printf("I am child, pid=%d,ppid=%d\n",getpid(),getppid());
15 break;//子进程退出循环的接口
16 }
17 else if(pid > 0){
18 //father
19 //printf("I am father, pid=%d,ppid=%d\n",getpid(),getppid());
20 }
21 }
22
23 sleep(i);
24 if(i < 5){
25 printf("I am child, will exit,pid=%d,ppid=%d\n",getpid(),getppid());
26 }
27 else{
28 //father
29 printf("I am parent, will out,pid=%d,ppid=%d\n",getpid(),getppid());
30 }
31
32 return 0;
33 }
>gcc nfork1.c
>./a.out
12、父子进程共享的内容
13、父子进程不共享全局变量
14、execlp函数介绍
15、exec函数规律
16、exel实现自定义程序
17、孤儿进程与僵尸进程
》孤儿进程:父亲死了,子进程被init进程领养。
》僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)。
wait函数简单使用和说明
wait回收并且查看死亡原因
waitpid回收子进程
用wait回收多个子进程
waitpid回收多个子进程
在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。