Linux编程(9)_进程

1 进程相关概念

1 程序和进程

程序: 二进制文件, 占用的磁盘空间

进程: 启动的程序, 所有数据都在内存, 不仅占用内存空间, 也需要占用更多的系统资源, 例如CPU, 物理内存

2 并行和并发

image.png

如图所示: 并发是两个队列交替使用一台咖啡机,并行是两个队列同时使用两台咖啡机

并发: 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。

并行: 是指“并排行走”或“同时实行或实施”。在操作系统中是指,一组程序按独立异步的速度执行,同一个时刻发生。要区别并发。并发是指:在同一个时间段内,两个或多个程序执行,有时间上的重叠(宏观上是同时,微观上仍是顺序执行)。

3 pcb 进程控制块

每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息, Linux内核的进程控制块是task_struct结构体

内部成员很多, 重点有:

  • 进程id. 系统中每个进程有唯一的id, 在C语言中用pid_t类型表示, 是一个非负整数
  • 进程的状态. 有就绪, 运行, 挂起, 停止等状态
  • 进程切换时需要保存和恢复的一些CPU寄存器
  • 描述虚拟地址空间的信息
  • 描述控制终端的信息
  • 当前工作目录
  • umask掩码
  • 文件描述符表(1024), 包含很多只想file结构体的指针
  • 信号相关的信息
  • 用户id和组id
  • 会话(Session)和进程组, 会话有多个进程组组成
  • 进程可以使用的资源上限(Resource Limit)
4 进程状态的切换

img

2 进程控制

1 fork

int fork(void) 生成父进程和子进程, 有两个返回值, 分别由父进程和子进程返回. 父进程返回子进程的PID, 子进程返回0, 出错则返回-1.

fork之后的变量读时共享, 写时复制.

  • fork函数的返回值

    >0, 父进程的返回值

    =0, 子进程的返回值

  • 子进程创建成功之后, 代码执行位置

    从父进程执行的位置开始执行, 忽略之前的代码

  • 父子进程的执行顺序

    不一定, 看谁先抢到cpu

  • 如何区分父子进程(通过返回值)

getpid() 获取当前进程的id

getppid 获取当前进程父进程的id

2 循环创建进程
int main() 
{
  int i = 0;
  int number = 5;
  pid_t pid;

  for(int i=0; i<number; ++i)
  {
    pid = fork();
    if(pid == 0) // 子进程跳出循环  
      break;  
  }

  //如何判断是第几个孩子
  //通过循环因子判断
  // 父进程
  if(i == 3)
  {
    counter += 100;
    printf("parent process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
    //  sleep(1);
  }
    // 子进程
  else if(i == 0)
  {
    // 1th
    counter += 200;
    printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
  }
  else if(i == 1)
  {
    // 2th
    counter += 300;
    printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
  }
  else if(i == 2)
  {
    // 3th
    counter += 400;
    printf("child process, pid = %d, ppid = %d, %d\n", getpid(), getppid(), counter);
  }

  return 0;
}
3 进程相关命令
  • ps

    ps aux | grep "xxx" 搜索进程

    ps ajx | grep "xxx" 更加全面的搜索进程

  • kill向指定的进程发送信号

    查看信号 kill -l

    杀死某个进程kill -9 PID

3 exec函数族

让父子进程执行不相干的操作

  1. 实现换核不换壳的功能

  2. 执行一个另外的程序不需要创建额外的地址空间

  3. 在当前程序调用另外一个的程序

    首先想到exec之前需要fork

  4. 如果函数执行成功, 没有返回值, 如执行失败, 打印错误信息, 退出当前进程.

1 执行指定目录下的程序
  • 原型int execl(const char *path, const char *arg, ...);

    path: 要执行的程序的路径

    变参arg: 要执行的程序的需要的参数

    第一个arg: 占位, 通常写执行程序的名字

    后面的arg: 命令的参数

    参数写完之后: NULL

    一般执行自定义程序

2 执行PATH环境变量里面的程序
  • 原型int execp(const char *file, const char *arg, ...);

    file: 执行的命令的名字

    第一个arg: 占位

    后边的arg: 命令的参数

    参数写完后: NULL

    执行系统自带的程序, 会在自动在目录/bin里搜索

    execlp("ps", "ps", "aux", NULL)

4 进程回收

1 孤儿进程

父进程已经被杀死, 子进程被init进程领养, init进程变成孤儿进程的父亲, ubuntu16.04变成被ui进程领养upstart

为了释放子进程占用的系统资源, 进程结束之后, 能够释放用户区空间, 释放不了pcb, 必须由父进程释放

2 僵尸进程

孩子进程被杀死, 父进程还活着, 爹不去释放子进程的pcb, 孩子进程就变成了僵尸进程

是一个已经死掉的进程

3 进程回收
  • wait 阻塞函数

    pid_t wait(int* status);

    返回值: -1: 失败, 已经没有子进程了. >0: 回收的子进程对应的pid

    参数: status 判断子进程是如何死的, 正常退出,或被某个信号杀死了

    调用一次只能回收一个子进程

  • waitpid –

    • pid_t waitpid(pid_t pid, int *status, int options);

5 进程相关函数

  1. pid_t fork(void);
    ○ 返回值:
    成功:

    ​ □ 对于父进程来说返回子进程ID

    □ 对于子进程来说返回值为0

    失败

    ​ □ 如果为-1表示创建失败

  2. 获取当前进程ID
    pid_t getpid(void);
    ○ 返回值:当前进程ID

  3. 获取当前进程的父进程ID
    pid_t getppid(void);

    ○ 返回值:前进程的父进程ID

  4. 获取当前进程实际用户ID
    uid_t getuid(void);

    ○ 返回值:当前进程实际用户ID

  5. 获取当前进程使用用户组ID
    gid_t getgid(void);

    ○ 返回值:前进程使用用户组ID

  6. int execl(const char *path, const char *arg, ...);
    ○ 函数描述:加载一个进程,通过路径 + 程序名来加载。
    函数参数:
    § path:程序路径+程序名字
    § arg:可执行程序的相关参数,使用NULL结尾

    返回值:
    § 成功:无返回
    § 失败:-1

  7. int execlp(const char *file, const char *arg, ...);
    函数描述:加载一个进程,借助PATH环境变量,
    该函数需要配合PATH环境变量来使用,
    当PATH中所有目录搜索后没有参数1则出错返回
    函数参数:可执行程序的相关参数,使用NULL结尾
    file:可执行程序的名字
    arg:可执行程序的相关参数,使用NULL结尾
    返回值:
    成功:无返回
    失败:-1

  8. pid_t wait(int *status);
    函数作用:
    ① 阻塞并等待子进程退出
    ② 回收子进程残留资源
    ③ 获取子进程结束状态(退出原因)。
    返回值:
    成功:清理掉的子进程ID;
    失败:-1 (没有子进程)
    参数:子进程的退出状态 – 传出参数
    1. WIFEXITED(status):为非0 → 进程正常结束
    WEXITSTATUS(status):
    如上宏为真,使用此宏 → 获取进程退出状态 (exit/return)的参数)
    2. WIFSIGNALED(status):为非0 → 进程异常终止
    WTERMSIG(status):
    如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。

  9. pid_t waitpid(pid_t pid, int *status, in options);
    函数作用:指定回收某个子进程
    参数:
    ① pid:
    pid == -1 回收所有子进程
    - 循环回收
    - while((wpid = waitpid(-1, $status, xx)) != -1) ???
    pid > 0 某个子进程的PID
    pid == 0 回收当前进程组的所有子进程
    pid < -1 子进程的PID取反
    ② status: 子进程的退出状态,用法同wait函数
    ③ options:
    设置为WNOHANG,函数非阻塞
    设置为0,函数阻塞
    返回值:
    >0:返回回收的子进程ID;
    -1:回收失败, 无子进程
    如果为非阻塞: =0 子进程正在运行。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值