Linux编程入门(13)-进程(一)

学习 Linux 编程,非常重要的一个知识点,便是进程。那进程是什么?如何用进程编写程序呢?让我们逐步揭开进程的面纱,攻克它,使得进程为我所用。

基础内容

什么是进程

运行一个程序意味着将机器指令序列载入内存,然后让 CPU 逐条执行这些指令。进程便是程序运行时的内存空间和设置。还有一种经典定义,进程是一个执行中程序的实例

Linux 在执行一个程序时,内核会将程序指令代码载入虚拟内存,为程序变量分配内存空间,建立记录进程信息的数据结构(如,进程 ID、用户 ID、组 ID、终止状态等)。

从内核角度来看,进程是一个个实体,内核在它们之间共享各种计算机内存资源。程序开始运行时,内核为其分配一定数量的资源。在进程的生命周期内,内核根据该进程对资源的需求,会进行相应的调整。程序终止时,内核会释放进程占有的所有资源。

进程的内存布局

进程为每个程序提供私有的地址空间。逻辑上这个地址空间分为以下几个部分:

  • 代码段,存放程序的指令。
  • 数据段,存放程序执行用到的数据变量。
  • 堆,程序动态分配内存的区域。
  • 栈,用于为局部变量和函数调用链接信息分配的内存空间。

进程用户 ID 和 组 ID

每个进程都有一组与之相关的用户 ID(UID) 和 组 ID(GID):

  • 真实用户 ID 和 组 ID:用来标识进程所属的用户和组。
  • 有效用户 ID 和 组 ID:进程在访问受保护资源时,会使用这两个 ID 来确定访问权限。

进程创建以及切换

进程的创建

创建一个新进程可以使用系统调用 fork()(后面会详细介绍)。调用 fork() 的进程称为父进程,新创建的进程则称为子进程。

内核通过复制父进程来创建子进程,子进程会从父进程那里继承数据段、栈段、堆段后,可以修改这些内容,不会对父进程造成影响。

子进程可以执行与父进程共享的代码段指令,也可以调用系统函数 execve() 去加载并执行一个全新的程序。

进程 ID

每个进程都有一个唯一的整数型进程标识符(PID)。另外,每个进程还具有一个父进程标识符(PPID),用以表示请求内核创建自己的进程。

进程切换

内核为每个进程维护一个上下文上下文是由程序正确运行所需的状态。状态包括,存放在内存中的程序代码和数据、栈、通用寄存器内容、程序计数器、环境变量、打开的文件描述符等。

当内核调度一个新进程运行时,它会抢占当前进程,使用上下文切换的机制将控制转移到新进程。进程切换步骤:

  • 保存当前进程的上下文。
  • 恢复先前被抢占的进程的上下文。
  • 将控制传递给这个新恢复的进程。

特殊进程

init 进程

init 进程是一种特殊的进程,在系统引导时由内核会创建。也可以称这个进程为 “所有进程之父”。系统中所有的进程,不是由 init 创建,就是由其后代进程创建的。

init 进程的进程 ID 总是为 1,且是以 root 权限运行。任何进程都不能 “杀死” init 进程,只有系统关闭才能终止该进程。

init 进程的主要任务是,创建并监控系统运行所需要的一系列的进程。

守护进程

守护进程是具有特殊用途的进程,有一些独有特性:

  • 不会退出。通常在系统引导时启动,在系统关闭之前,一直存在。
  • 在后台运行,无控制中断供其读取或写入数据。

查看当前运行的进程

进程存在于用户空间。运行的程序的指令和数据,有一部分内容存放在用户空间。可以通过 ps (process status 进程状态的简写)指令来查看用户空间的内容。这个命令会列出当前的进程:

$ ps

  PID TTY          TIME CMD
 7356 pts/0    00:00:00 bash
 7364 pts/0    00:00:00 ps

由命令执行结果看出,有两个进程在运行:bash 和 ps 指令。每个进程都有唯一的进程标识符(PID)。这两个进程都与一个终端(TTY)相连,此处是 /dev/pts/0。接着是进程已经运行的时间。最后是创建此进程执行的命令。

ps 指令有许多选项。 支持 -a 选项,列出所有进程,包括在其他终端由其他用户运行的程序:

$ ps -a

  PID TTY          TIME CMD
 1616 tty1     00:00:00 gnome-session-b
 1622 tty1     00:00:13 gnome-shell
 1637 tty1     00:00:00 Xwayland
 1686 tty1     00:00:00 ibus-daemon
 1689 tty1     00:00:00 ibus-dconf
 1692 tty1     00:00:00 ibus-x11
 1749 tty1     00:00:00 gsd-xsettings
 1761 tty1     00:00:00 gsd-a11y-settin
 1762 tty1     00:00:00 gsd-clipboard
 1765 tty1     00:00:01 gsd-color
 1766 tty1     00:00:00 gsd-datetime
 1771 tty1     00:00:00 gsd-housekeepin
 1772 tty1     00:00:00 gsd-keyboard
 1773 tty1     00:00:00 gsd-media-keys
 1774 tty1     00:00:00 gsd-mouse
 1779 tty1     00:00:00 gsd-power
 1782 tty1     00:00:00 gsd-print-notif
 ...
 6925 tty2     00:00:04 gnome-software
 7015 tty2     00:00:00 deja-dup-monito
 7449 pts/0    00:00:00 ps

ps 指令也有 -l 选项,可以打印更多细节:

$ ps -l

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  7356  7346  0  80   0 -  6117 wait   pts/0    00:00:00 bash
0 R  1000  7474  7356  0  80   0 -  7667 -      pts/0    00:00:00 ps

S 列表示各个进程的状态,S 列中的 R 说明 ps 对应的进程正在运行。其他进程为 S,说明它们处于休眠状态。每个进程都属于由 UID 列指明的用户 ID。进程 ID (PID)和父进程 ID(PPID)也会打印显示出来。

标记为 PRI 和 NI 的列分别是进程的优先级和 nice 值。内核根据这些值来决定何时运行进程。

SZ 列表示一个进程的大小。这列的数据实际上是,这个进程占用的内存大小。

WCHAN 列显示进程睡眠的原因。上面的例子中,bash 进程处于睡眠状态,睡眠原因是等待输入。

F 和 ADDR 已经不再使用,但是为了兼容的原因而保留它们。

ps 指令还有许多其他选项,感兴趣的话可以自己查阅相关资料。

小结

本文主要介绍了进程的基础知识:

  • 进程的概念
  • 进程的内存布局
  • 进程创建和切换
  • 两种特殊进程
  • 查看进程的一些信息

关注公众号【一起学嵌入式】,获取更多精彩内容

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zsky_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值