【Linux】初识进程控制

进程概念

  • 用户角度:进程是程序一次动态的执行过程。
  • 操作系统:进程是操作系统分配资源的最小单位。
    硬件上有中断技术出现,产生了分时系统。
    进程有自己的运行状态和地址空间(虚拟地址空间)。

描述进程—PCB

进程信息被放在一个叫进程控制块的数据结构中,可以理解为进程属性的集合。
Linux操作系统下的PCB是:task_struct
tast_struct内容分类:

  • 标识符
  • 状态
  • 优先级
  • 程序计数器
  • 内存指针
  • 上下文数据
  • I/O状态信息
  • 记账信息
  • 其他信息
进程和程序区别:

程序:完成特定任务的一系列指令的有序集合。
进程与程序的区别;

  • 进程是动态的运行过程,程序是静止的。
  • 进程有PCB.
  • 进程是短暂的,程序相对永久。
  • 一个进程只能对应一个程序,一个程序可以对应多个进程。

创建进程

fork():

  • 分配进程标识符
  • 创建PCB
  • 复制父进程的环境
  • 给子进程分配内存空间,将父进程的数据拷贝到该地址空间
  • 将子进程置为就绪状态,放入就绪队列。
    代码:
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4   
  5 int main()
  6 { 
  7         int ret=fork();
  8         if(ret<0)
  9         {   
 10                 perror("fork");
 11                 return 1;
 12         }           
 13         else if(ret==0)//子进程
 14         {   
 15                 printf(" i am child %d!,ret :%d\n",getpid(),ret);
 16         }   
 17         else        
 18         {   
 19  
 20                 printf(" i am father %d!,ret :%d\n",getpid(),ret);
 21         }
 22         sleep(1);   
 23         return 0;
 24 }

这里写图片描述
vfork():创建子进程,子进程和父进程共享地址空间,保证子进程先运行,在它调用exec或exit(0)之后父进程才能被调度。

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7         pid_t pid;
  8         pid=fork();
  9         if(pid<0)
 10         {
 11                 perror("fork"),exit(1);
 12         }
 13         else if(pid==0)//子进程
 14         {
 15             //  sleep(5);
 16                 printf(" i am child %d\n",getpid());
 17         }
 18         else//父进程
 19         {
 20 
 21                 printf(" i am father %d\n",getpid());
 22         }
 23 
 24         exit(0);
 25 }

这里写图片描述


进程终止

正常终止:

  • 从main返回
  • 调用exit
1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 void handler()
  5 {
  6         printf("这是一个锦囊\n");
  7 }
  8 void handler2()
  9 {
 10 
 11         printf("这是一个锦囊2\n");
 12 }
 13 int main()
 14 {
 15         atexit(handler);
 16         atexit(handler2);
 17         printf("hehe\n");
 18         fprintf(stderr,"error");
 19         sleep(2);
 20         exit(0);       
 21 }       
 22         
 23         

这里写图片描述
- _exit

调用_exit函数

1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 void handler()
  5 {
  6         printf("这是一个锦囊\n");
  7 }
  8 void handler2()
  9 {
 10 
 11         printf("这是一个锦囊2\n");
 12 }
 13 int main()
 14 {
 15         atexit(handler);
 16         atexit(handler2);
 17         printf("hehe\n");
 18         fprintf(stderr,"error");
 19         sleep(2);
 20         _exit(0);       
 21 }       
 22         
 23         

这里写图片描述

由此可以看出exit最后也会调用_exit,但还做了其他工作:

  • 执行用户通过atexit或 on_exit定义的清理函数
  • 关闭所有打开的流,所有缓存数据均被写入
  • 调用_exit

    异常终止

  • kill pid:杀死进程

  • ctrl+c:信号终止
  • abort():使程序不正常结束

进程等待

父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息。
wait
waitpid
这里写图片描述

  • 进程的阻塞等待:
1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/wait.h>
  5 
  6 int main()
  7 {
  8         pid_t pid=fork();
  9         if(pid<0)
 10         {
 11                 perror("fork"),exit(1);
 12         }
 13         else if(pid==0)//子进程
 14         {
 15                 printf("I am child ,pid is %d\n",getpid());
 16                 sleep(5);
 17                 exit(666);
 18         }
 19         else
 20         {
 21                 int status=0;
 22                 pid_t ret=waitpid(-1,&status,0);//阻塞式等待,等价于wait(&status)
 23                 printf("this is a wait test\n");
 24                 if(WIFEXITED(status)&&ret==pid)
 25                 {
 26                         printf("wait child 5s success,child return code id %d\n",WEXITSTATUS(status));
 27                 }
 28                 else
 29                 {
 30                         printf("wait child failed,return \n");
 31                         return 1;
 32                 }
 33 
 34         }
 35         return 0;
 36 }

这里写图片描述
- 进程的非阻塞等待:

int main()
  7 {
  8         pid_t pid=fork();
  9         if(pid<0)
 10         {
 11                 perror("fork"),exit(1);
 12         }       
 13         else if(pid==0)//子进程
 14         {
 15                 printf("I am child ,pid is %d\n",getpid());
 16                 sleep(5);
 17                 exit(666);
 18         }       
 19         else
 20         {
 21                 int status=0;
 22                 pid_t ret=0;
 23                 do
 24                 {
 25                         ret=waitpid(-1,&status,WNOHANG);//非阻塞等待,
 26                         if(ret==0)
 27                         {
 28                                 printf("child is ruining\n");
 29                         }
 30                         sleep(1);
 31                 }while(ret==0);
 32                 if(WIFEXITED(status)&&ret==pid)
 33                 {
 34                         printf("wait child 5s success,child return code id %d\n",WEXITSTATUS(status));
 35                 }
 36                 else
 37                 {
 38                         printf("wait child failed,return \n");
 39                         return 1;
 40                 }
 41 
 42         }
 43         return 0;
 44 }

这里写图片描述

此外wait还可以回收僵尸子进程
所谓僵尸子进程:一个进程被终止,但未被其父进程回收的进程。
waitpid可以被一个进程用来等待他的子进程终止。


进程替换

替换函数
这里写图片描述

当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新数据替换,从新程序的启动例程开始执行。调用exec并不创建新进程,故调用exec前后该进程ID不变。

例如;execve函数
这里写图片描述
execve函数加载并运行可执行目标文件filename,且带参数列表argv 和环境变量列表envp,只有调用出错时,返回到调用程序,若调用成功则加载新的程序从启动代码开始执行,不再返回。

argv 变量指向一个以NULL结尾的指针数组,其中每个指针都指向一个参数串;envp变量也指向一个以NULL结尾的指针数组,其中每个指针都指向一个环境变量串,其中每个串都是形如“‘NAME=VALUE”。
这里写图片描述
这里写图片描述

 1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 
  5 //l(list):表示参数采用列表
  6 //v(vector):参数用数组
  7 //p(path):有p自动搜索环境变量PATH
  8 //e(env):表示自己维护环境变量
  9 int main()
 10 {
 11         char *const argv[]={"ps","-ef",NULL};
 12         char *const envp[]={"PATH=/bin:/usr/bin","TERM=console",NULL};
 13         printf("before exec\n");
 14         //execl("/bin/ps","ps","-ef",NULL);
 15         //带p的:可以使用环境变量PATH,无需写全路径
 16         //execlp("ps","ps","-ef",NULL,envp);
 17         //带e的,需要自己组装环境变量
 18         //execle("ps","ps","-ef",NULL,envp);
 19         //execv("/bin/ps",argv);
 20         //execvp("ps",argv);
 21         execve("/bin/ps",argv,envp);
 22 
 23         printf("thanks to \n");
 24         exit(0);
 25 }

这里写图片描述


用进程相关操作实现简易的myshell

 1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/wait.h>
  5 #include<string.h>
  6 #include<ctype.h>
  7 
  8 #define MAXLINE 1024 
  9 
 10 char *argv[8];
 11 int argc;
 12 char cmdline[MAXLINE+1];
 13 int init()
 14 {
 15         argc=0;
 16         memset(cmdline,0x00,sizeof(cmdline));
 17 }
 18 int read_cmd()
 19 {
 20         return fgets(cmdline,MAXLINE,stdin)==NULL ? 0:1;
 21 }
 22 int parse_cmd()
 23 {
 24         int flag=0;
 25         int i;
 26         for(i=0;cmdline[i]!='\0';i++)
 27         {
 28                 if(flag==0&&!isspace(cmdline[i]))
 29                 {
 30                         flag=1;
 31                         argv[argc]=cmdline+i;
 32                         argc++;
 33                 }
 34                 else if(isspace(cmdline[i]))
 35                 {
 36                         flag=0;
 37                         cmdline[i]='\0';
 38                 }
 39         }
 40         argv[argc]=NULL;
 41 }
 42 int execute_cmd()
 43 {
 44         if(fork()==0)
 45         {
 46                 execvp(argv[0],argv);
 47                 exit(1);
 48         }
 49         wait(NULL);
 50 }
 51 void print_cmd()
 52 {
 53         int i;
 54         printf("argc=%d\n",argc);
 55         for(i=0;i<argc;i++)
 56         {
 57                 printf("\targv[%d]=%s\n",i,argv[i]);
 58         }
 59 }
 60 int main()
 61 {
 62         while(1)
 63         {
 64                 init();
 65                 printf("shell>");
 66                 if(read_cmd()==0)//从键盘上读取
 67                 {
 68                         break;
 69                 }
 70                 parse_cmd();//解析
 71                 print_cmd();
 72                 execute_cmd();//执行
 73         }
 74 }

这里写图片描述

猜你喜欢

转载自blog.csdn.net/mmwwxx123/article/details/81288222