进程控制

进程创建
fork
从已经存在的进程创建一个进程,新进程称为子进程,原进程称为父进程,调用此函数子进程返回0,父进程返回子进程的进程ID

进程调用fork之后:
  1. 分配新的内存和数据块给子进程
  2. 将父进程的数据拷给子进程


调用失败的原因:
  1. 系统内有太多的进程
  2. 实际用户的进程数达到了最大值


fork之后父子进程一起执行代码,但是谁先执行由调度器决定
通常父子进程的代码共享,当父子进程不在写入数据的时候,此时数据也共享,但是当父子进程任一方写入数据时,便以写时拷贝的方式各自拷贝一个副本

int main()
{
  pid_t ret = fork();
  printf( "ret = %d\n,pid = %d\n,ppid = %d\n" ,ret,getpid(),getppid());
  return 0;
}


vfork
概念:
  1. vfork创建的进程共享同一块地址空间
  2. vfork后的子进程先执行,在子进程调用完exec之后,父进程再执行
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
  pid_t id = vfork();
  if (id == 0)
  {
    g_val = 200;
    printf( "before: [%d],pid:[%d],ppid:[%d]\n" ,g_val,getpid(),getppid());
    exit(0);
  }
  else if (id > 0)
  {
    printf( "after: [%d],pid:[%d],ppid:[%d]\n" ,g_val,getpid(),getppid());
  }
 
  return 0;
}


我们可以发现g_val的值改变了,这就证明事实上父子进程就是共享地址空间

进程终止
退出情况
  1. 代码运行完成,结果正确
  2. 代码运行完成,结果不正确
  3. 代码运行时一场终止

退出方式
  1. 正常退出(main函数返回,调用exit,调用_exit) 用echo $? 来查看进程的退出码
  2. 异常退出(ctrl+c异常终止)

_exit函数( 系统调用
  1. 函数原型:void _exit(int status);
  2. status中定义了进程的终止状态,但是只有低8位可以用

exit函数
  1. void exit(int status);
  2. 底层还是调用了_exit系统调用
  3. 但是在调用_exit之前,执行清理函数,关闭了所有打开的文件描述符


我们可以画个图来理解一下


return:return n 即 exit(n),因为调用main的函数运行时会将main的返回值当做exit的参数


进程等待
当子进程退出,如果父进程不管不顾,此时子进程就会变成僵尸进程,造成内存泄漏,并且此时用kill指令也杀不死这个进程,因为谁也没办法杀死一个已经死去的进程,此时进程等待就尤为重要

进程等待的方法
  1. pid_t wait(int status):成功返回进程等待的子进程的id,失败返回-1,输出型参数,得到进程的返回状态
  1. pid_t waitpid(pid_t pid,int status,int options);正常返回等待进程的pid,调用出错返回-1
  2. 此时的进程等待都是阻塞式等待,就是只要子进程没有结束,那么父进程就一直啥也不干,就一直等待子进程结束

在进程等待的时候
  1. 当我们使用wait,waitpid等待进程的时候,如果等待的该进程已经退出的话,那么函数直接返回,释放资源,获得子进程的退出信息
  2. 如果在任意时刻调用wait/waitpid的时候,如果子进程没有退出且正在运行,那么父进程就会一直阻塞式的等待
  3. 如果不存在该进程,那么直接出错返回

获取子进程的退出状态(status)
  1. status:我们可以用命令echo $?  获取到现在为止的最近的进程的退出状态,它是一个输出型参数,我们可以把它当做一个位图来理解

这张图只是status的低16比特位,那在代码里我们也可以这样获取进程的退出状态

正常退出:status & 0x7f == 0; 获得进程的退出码:(status >>8) &0xff
异常退出状态:返回一个终止的信号码:status & 0x7f


进程的程序替换
我们在用fork创建子进程之后,子进程执行的是和父进程相同的代码,但有可能是代码的不同分段,所以子进程往往要带哦用exec函数(一簇代码,并不是一个代码)去执行其他的代码。当进程调用exec函数的时候,进程的数据和代码全部被新程序替换,从新的代码开始执行,但是调用exec函数不会产生新进程,所以该子进程的进程ID是没有改变的

我们来了解一下这6个exec函数


path:路径 
file:文件名
argv:参数所用的数组
envp:环境变量表
这些函数执行成功了之后不会返回任何东西,但是一旦执行失败,则会返回-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值