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

进程创建

pid_t fork(void)

通过复制父进程创建子进程,父子进程代码共享,资源独有

fork()的返回值:(用于区分父子进程)
父进程,返回子进程的pid,大于0
子进程,返回0
出错时返回-1
在这里插入图片描述
在这里插入图片描述

pid_t vfork(void)—这种方法用的很少

–创建一个子进程并阻塞父进程,父子进程共用虚拟地址空间
–如果父子进程同时运行会造成栈混乱,所以vfork()阻塞了父进程,让子进程先运行,直到子进程exit退出或者程序替换后,父进程才能继续运行

写时拷贝技术

通过复制父进程创建子进程,所以父子进程一开始映射的是同一块物理内存地址,但是当数据需要发生改变时,则重新为子进程开辟新的空间,将数据拷贝过去
优点:创建子进程的效率高

进程退出

1、main函数中的return

只有main函数中的return可以退出进程,其他地方不可以

2、库函数 void exit(int status)

可以在任意位置调用退出进程,退出前刷新缓冲区

3、系统调用接口 _void exit(int status)

可以在任意位置调用退出进程,不刷新缓冲区
status可以视为进程的退出返回值,即程序的退出原因,保存在pcb中
使用ehco &?命令 可以获取 上一个已退出进程的status值

查看上一次系统调用使用错误的原因

1、void perror(const char* s);

打印一个系统错误信息
const char* s为用户自定义的备注信息,例如:

在这里插入图片描述
在这里插入图片描述
表示程序运行成功,未出现错误。
2、char *strerror(int errnum);

errnum–全局变量,程序错误序号
通过程序错误序号获取错误信息

进程等待

父进程等待子进程推出,获取其退出返回值,释放子进程的资源

目的:避免产生僵尸进程

头文件:#include <sys/wait.h>

1、 pid_t wait(int *status);

阻塞等待任意一个子进程退出,通过status获取退出返回值,释放资源
**返回值:**若成功,返回退出的子进程的pid;若出错,返回-1

2、pid_t waitpid(pid_t pid, int *status, int options);

可以等待任意一个子进程退出,也可以等待指定的子进程退出
pid_t pid:等于-1,表示等待任意子进程退出;大于0,表示等待指定子进程退出
可以是阻塞等待子进程退出,也可以是非阻塞等待子进程退出
int options:设置为0,执行阻塞等待;设置为WNOHANG,则执行非阻塞等待
返回值:

若成功,返回子进程pid;
若没有子进程退出,返回0(非阻塞状态下,阻塞状态下会一直等待);
出现错误,返回-1

注意:如果有已经退出的子进程,wait/waitpid会直接处理,无需等待

阻塞和非阻塞

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

代码示例:
   #include<stdio.h>
   #include<stdlib.h>
   #include<unistd.h>
   int main()
   {
     int pid=fork();
     if(pid<0)
     {
       //出错
      perror("fork error");
      return -1;
    }
    else if(pid==0)
    {	//子进程
      sleep(5);//休眠5秒
     return 99;//main中的return--退出子进程,退出返回值为99
    }
    else
    {
      //父进程
      while(1)sleep(1);//保持休眠
    }
                                                                                                                      
    return 0;
  
  }

在这里插入图片描述

子进程休眠5秒后退出,进入僵尸态,会发生内存泄漏
下面修改代码,加入内存等待操作

   #include<stdlib.h>
   #include<unistd.h>
   #include<sys/wait.h>
   int main()
   {
     int pid=fork();
     if(pid<0)
     {
      //出错
      perror("fork error");
      return -1;
    }
    else if(pid==0)
    {
      //子进程
      sleep(5);
      return 99;//main中的return--退出子进程,退出返回值为99
    }
    //int ret=waitpid(-1,NULL,0);   //与21行等价,用哪个都行
    int ret=wait(NULL);//等待任意子进程退出
 
    printf("progress:%d exit\n",ret);                                                                                 
      //父进程
      while(1)sleep(1);//死循环
 
  
    return 0;
  }

在这里插入图片描述

打印信息:pid=6035的子进程退出

在这里插入图片描述

结果显示子进程直接退出,已经不存在了

再来看waitpid非阻塞状态的代码:

   #include<stdio.h>                                                                                                   
   #include<stdlib.h>
   #include<unistd.h>
   #include<sys/wait.h>
   int main()
   {
     int pid=fork();
     if(pid<0)
     {
      //出错
      perror("fork error");
      return -1;
    }
    else if(pid==0)
    {
      //子进程
      sleep(5);
      return 99;//main中的return--退出子进程,退出返回值为99
    }
    
   // int ret=wait(NULL);
   // printf("progress:%d exit\n",ret);
    int ret; 
    while((ret=waitpid(-1,NULL,WNOHANG))==0)
      {
        //非阻塞状态下,没有子进程退出,返回0
        printf("当前子进程还没有退出\n");
        sleep(1);
      }
      if(ret<0)
      {
        perror("waitpid error:");
      }
      printf("progress:%d exit\n",ret);
   //父进程
      while(1)
      {
        sleep(1);//死循环
      }                                                                                                               
    return 0;
    
  }


在这里插入图片描述

进程替换

替换一个进程正在调度运行的程序
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。
调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

6种进程替换函数

#include <unistd.h>`
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[]);

函数解释

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。

命名理解

l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量

函数名参数格式带路径?使用当前环境变量?
execl列表不是
execlp列表
execle列表不是不是,必须自己组装环境变量
execv数组不是
execvp数组
execve数组不是不是,必须自己组装环境变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值