当前位置:   article > 正文

Linux入门篇——进程控制_头歌linux之进程管理二

头歌linux之进程管理二

1 进程创建

2 进程终止

1.进程退出场景

(1)代码运行完毕,结果正确 退出码为0
(2)代码运行完毕,结果不正确 退出码非0
(3)代码异常终止 程序崩溃,退出码无意义

2. 进程常见退出方法

(1)正常终止:

  • 从main返回,刷新缓冲区
  • 调用exit,刷新缓冲区
  • _exit 接口,强制终止进程,不进行进程的收尾工作(执行用户定义的清理函数、冲刷缓冲、关闭流等)

(2)异常退出

  • ctrl+c,信号终止
    ————————————————补充————————————————
1.$?:最近一次进程退出的退出码
#include<stdio.h>
int main(){
  printf("return 12\n");
  return 12;
}
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述
12是进程myproc的退出码(main函数的返回值 )
0是第一条echo的退出码

2. 非main函数返回:

函数返回

3.exit(int status):终止进程

参数:退出码
—————————————————————————————————————

3 进程等待

父进程通过wait/waitpid等待子进程退出
为何让父进程等待?
1.通过获取子进程退出的信息,得到子进程执行的结果
2.可以保证:时序问题,子进程先于父进程退出
3.子进程退出,父进程不管不顾,可能进入僵尸状态,造成内存泄漏,需要通过父进程wait释放子进程占用的资源
在这里插入图片描述
通过stat_loc可以获取子进程退出的信息:
正常退出:第8-15位是子进程退出码,0-7位是退出信号(正常退出则为0)
子进程正常退出
被信号所杀:第0-6位是终止信号,第七位是core dump标志,不使用8-15
被信号所杀,信号8:SIGFPE,算术错误

#include <stdio.h>
#include <sys/types.h> //wait
#include <sys/wait.h> // wait
#include <stdlib.h> // exit
#include <unistd.h> // fork
//进程等待 wait
//子进程运行5s,父进程sleep10s,后5s子进程成为僵尸进程
//10s后父进程执行wait,回收子进程
int main(){
  pid_t pid = fork();
  if(pid == 0){
    int cnt = 3;
    while(cnt){
      printf("child[%d] is running,cnt = %d\n",getpid(),cnt);
      cnt--;
      sleep(1);
    }
    // 浮点型错误,退出信号=8
    //int a = 10;
    //a/=0;

    exit(11);
  }
  sleep(5);
  //pid_t ret = wait(NULL);// 返回等待的子进程pid或-1,参数是退出码

  //pid_t ret = waitpid(pid,NULL,0);// 返回值同上,pid设成1时等待任意一个子进程
 
  int status = 0;
  pid_t ret = waitpid(pid,&status,0);
  if(ret>0){
    // //printf("father wait:%d,status exit code:%d,status exit signal:%d\n",ret,(status>>8),status);
    //printf("father wait:%d,status exit code:%d,status exit signal:%d\n",ret,(status>>8)&0xFF,status&0x7F);
  
    if(WIFEXITED(status)){// 没有收到退出信号
      // 正常结束的 获取对应退出码
      printf("exit code:%d\n",WEXITSTATUS(status));
    }else{
      printf("error,get a signal\n");
    }
  }else{
    printf("father failed\n");
  }
  return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

进程的等待方式:
(1)阻塞等待:
阻塞的本质是进程的PCB被放入等待队列,并将进程的状态修改为S状态
返回的本质是进程的PCB从等待队列拿到R队列,从而被CPU调度

waitpid(-1,&sataus,0);
  • 1

(2)非阻塞等待
不断调度父进程
基于非阻塞的轮询等待方案

int ret = waitpid(-1,&sataus,WNOHANG);// WNOHANG:不阻塞模式
if(ret == 0){
  //子进程没有退出,但是waitpid等待是成功的,需要父进程重复进行等待
}else if(ret > 0){
  // 子进程退出了,waitpid也成功,获取了对应结果
}else{
  //等待失败
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4 进程程序替换

进程不变,仅仅替换当前进程的 代码和数据
只要程序替换成功,就不会执行后续代码/ exec* 函数成功的时候不需要返回值检测,若exec*返回了就一定是调用失败了

为什么要程序替换:

让子进程执行一个“全新的程序”

程序替换函数的使用:

在这里插入图片描述
execve:系统调用
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg,…, char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
int execve(const char *filename, char *const argv[],char *const envp[]);

参数:const char *path:要执行的目标程序的全路径(所在路径/文件名)
const char *arg, …:要执行的目标程序,可变参数列表,以NULL作为传参的结束

      execl("/usr/bin/ls","ls","-a","-l","-i",NULL);    
        
      char *argv[]={"ls","-a","-l","-i",NULL};    
      execv("/usr/bin/ls",argv);    
      
      execlp("ls","ls","-a","-l","-i",NULL);    
      
      execvp("ls",argv);    
          
      execl("./myexe","myexe",NULL);// 程序调换 调用我的另一个程序    
      
      char *env[] = {"MYENV=myenv","MYENV2=myenv",NULL};    
      execle("./myexe","myexe",NULL,env);    
      
      char *argv1[]={"myexe",NULL};    
      execve("./myexe",argv1,env);     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/336669
推荐阅读
相关标签
  

闽ICP备14008679号