Linux系统编程——09-linux-day05(进程控制)

    技术2022-07-10  143

    在学习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,转载请注明出处。

    Processed: 0.017, SQL: 9