Linux入门篇——进程控制

1 进程创建

2 进程终止

1.进程退出场景

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

2. 进程常见退出方法

(1)正常终止:

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

(2)异常退出

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

Linux入门篇——进程控制_第1张图片
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)
Linux入门篇——进程控制_第2张图片
被信号所杀:第0-6位是终止信号,第七位是core dump标志,不使用8-15
Linux入门篇——进程控制_第3张图片

#include 
#include  //wait
#include  // wait
#include  // exit
#include  // 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)阻塞等待:
阻塞的本质是进程的PCB被放入等待队列,并将进程的状态修改为S状态
返回的本质是进程的PCB从等待队列拿到R队列,从而被CPU调度

waitpid(-1,&sataus,0);

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

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

4 进程程序替换

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

为什么要程序替换:

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

程序替换函数的使用:

Linux入门篇——进程控制_第4张图片
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);     

你可能感兴趣的:(os,linux,bash,运维)