Linux进程控制

进程控制:创建、退出、等待、替换

  1. 创建:
    pid_t fork(void)—通过复制父进程创建一个子进程。(代码共享,数据独有)
    返回值:父进程返回值大于0(子进程pid);子进程返回0;出错返回-1
    写时拷贝技术:创建子进程后,子进程复制了父进程,因此父子进程一开始映射的是同一块物理内存,但是当内存数据要发生改变的时候,则重新为子进程开辟空间,拷贝数据过去。—创建子进程效率高

    pid_t vfork(void)—创建一个子进程并阻塞父进程。(父子进程共用虚拟地址空间)
    父子进程共用栈区,如果同时运行就会造成栈混乱,因此vfork阻塞父进程,让子进程先运行,直到子进程exit退出或者程序替换后,父进程才会运行。

  2. 退出:
    main函数中return
    库函数:void exit(int status)—可以在任意位置调用退出进程,在退出前会刷新缓冲区
    系统调用:void _exit(int status)—可以在任意位置调用退出进程,但是会直接释放资源,不刷新缓冲区
    获得进程退出返回值:echo $?

    退出场景:
    正常退出:通过以上三种方式退出进程
    异常退出:程序因为某种错误中间崩溃退出

    查看上一次系统调用使用错误的原因:
    void perror(const char* s)
    char* strerror(int errnum)

  3. 进程等待:
    父进程等待子进程退出,获取退出子进程返回值,释放退出的子进程资源—避免产生僵尸进程

    接口头文件:#include<sys/wait.h>
    pid_t wait(int* status)—阻塞接口
    等待任意一个子进程退出,通过status获取退出返回值,释放资源。
    返回值:成功则返回退出子进程的pid>0;错误返回-1

    pid_t waitpid(pid_t pid, int* status, int options)
    可以等待任意一个子进程退出,也可以等待指定的子进程退出
    可以阻塞等待子进程退出,也可以非阻塞等待子进程退出。
    参数设置:pid:-1—等待任意子进程;大于0—等待指定子进程;
    options:0—默认阻塞等待;WNOHANG-非阻塞等待
    返回值:成功则返回退出子进程的pid>0;没有子进程退出返回0;错误返回-1

    阻塞:为了完成一个功能,发起一个调用,若功能完成条件不具备,一直等待。
    非阻塞:为了完成一个功能,发起一个调用,若功能完成条件不具备,立即报错返回。

    注意:wait/waitpid是只要有已经退出的子进程,则会直接处理,不需要等待

    pcb里保存进程退出返回值时到底是怎么保存的?获取的status值到底是什么数据?
    在这里插入图片描述
    注意:WIFEXITED返回真代表进程正常退出,之后才可使用WEXITESTATUS

进程等待以及查看子进程退出返回值的代码实现:

 #include <stdio.h>   //printf
 #include <stdlib.h>   //exit
 #include <unistd.h>   //fork
 #include <sys/wait.h>   //wait                                                                                                   
 
 int main()
 {
   pid_t pid = fork();   //创建子进程 
   if(pid < 0)
   {
     perror("fork perror");   //若返回值小于0代表子进程创建失败
     return -1;
   }
   else if(pid == 0)
   {
     printf("i am child process\n");   //返回值等于0代表是子进程
     sleep(5);
     exit(99);   //五秒后子进程退出,退出码为99
   }
   int ret, status;
   while((ret = waitpid(-1, &status, WNOHANG)) == 0)   //父进程循环非阻塞等待子进程退出,并获取子进程返回值status
   {
     printf("当前子进程还没有退出\n");   //若waitpid返回值为0表示当前子进程还没有退出
     sleep(1);
   }
   if(ret < 0)   //waitpid出错返回-1
   {
     perror("waitpid error");
   }
   if((status & 0x7f) != 0)   //低7位为异常退出信号值,若为0表示进程正常退出
   {
     printf("进程异常退出");
     return -1;
   }
   int retval = (status >> 8) & 0xff;   //低16位中的高8位为进程正常退出的返回值
   int coredval = (status >> 7) & 0x01;   //获取coredump标志位
   printf("%d-%d, exit-retval:%d, coredval:%d\n", ret, pid, retval, coredval);   //打印子进程pid,退出码以及coredump标志位
   return 0;

运行结果:
在这里插入图片描述

  1. 程序替换:替换一个进程正在调度运行的程序(加载一个新的程序到内存中,更新当前进程的页表映射信息到新的程序上)
    exec函数族:5个库函数+系统调用接口
    extern char** environ;
    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 execve(const char* path, char* const argv[], char* const envp[])
    3类参数:新的程序路径名称;程序运行参数(最后必须要以NULL作为结尾);自己设定环境变量

    execl和execv的区别:程序运行参数的不同设置方式
    例:execl("/bin/ls", “ls”, “-a”, “-l”, NULL)
    char* argv[] = {“ls”, “-a”, “-l”, NULL};execv("/bin/ls", argv)

    execl(execv)和execlp(execvp)的区别:新的程序是否需要带路径,指定程序所在位置
    execl("/bin/ls", …)
    execlp(“ls”, …)—原因是会到PATH环境变量指定的路径下去找对应程序,适用场景:要替换的为命令程序(也可以通过指定新程序的路径实现功能)

    execl(execv)和execle(execve)的区别:当前进程的环境变量是否由自己来设置
    execl("/bin/ls", …)—使用默认当前就有的环境变量
    char* env[] = {“MYVAL=1000”, NULL};execle("/bin/ls", …, NULL, env)—直接替换原有环境变量,而非追加,即此时只有一个环境变量MYVAL

exec函数族测试:

#include <stdio.h>    
#include <stdlib.h>    
#include <unistd.h>    
    
int main()    
{    
  printf("我要进行程序替换啦~~\n");    
    
  //extern char** environ;   //获取当前进程环境变量    
  //char* env[] = {"MYVAL = 1000", NULL};   //自己设置当前进程环境变量    
    
  execl("/usr/bin/ls", "ls", "-a", "-l", NULL);    
    
  //execlp("ls", "ls", "-a", "-l", NULL);    
    
  //execle("/usr/bin/ls", "ls", "-a", "-l", NULL, env);    
    
  //char* argv[] = {"ls", "-a", "-l", NULL};   //定义指针数组存储程序运行参数                                                        
    
  //execv("/usr/bin/ls", argv);    
    
  //execvp("./myenv",argv);    
    
  //execve("./myenv", argv, environ);    
  printf("程序替换结束\n");    
  return 0;    
}

①execl,execlp,execv,execvp运行结果:
在这里插入图片描述

②通过自己设置当前进程的环境变量测试execve

#include <stdio.h>    
#include <stdlib.h>    
#include <unistd.h>    
    
int main()    
{    
  printf("我要进行程序替换啦~~\n");    
    
  extern char** environ;   //获取当前进程环境变量    
  char* env[] = {"MYVAL = 1000", NULL};   //自己设置当前进程环境变量    
    
  //char* argv[] = {"ls", "-a", "-l", NULL};   //定义指针数组存储程序运行参数                                                        
    
  execve("./myenv", argv, env);    
  printf("程序替换结束\n");    
  return 0;    
}

打印当前输入命令参数以及当前进程环境变量:

  #include<stdio.h>    
  #include<unistd.h>    
  #include<stdlib.h>    
      
	int main(int argc, char* argv[])    
  {    
    for(int i = 0; argv[i] != NULL; i++)    
    {    
      printf("argv[%d] = %s\n", i, argv[i]);    
    }    
    extern char** environ;    
    for(int i = 0; environ[i] != NULL; i++)    
    {    
      printf("environ[%d] = %s\n", i, environ[i]);                                                                                   
    }    
    return 0;    
  }    

运行结果:
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值