深入理解程序、进程与并发的奥秘

资料合集
链接:https://pan.quark.cn/s/770d9387db5f

从“剧本”到“戏剧”:

当我们双击一个应用图标,或者在终端敲下 ​
​./a.out​
​ 并回车时,一个神奇的转换发生了:一个静静躺在硬盘上的文件,瞬间“活”了过来,变成了屏幕上一个可以交互的窗口或后台运行的任务。

这个从静态到动态的飞跃,正是计算机科学中两个最基本的概念——程序(Program)与进程(Process)——的核心区别。理解它们,就等于拿到了进入操作系统殿堂的第一把钥匙。

一、 静态的“剧本”:到底什么是程序?

在我们探讨“运行”之前,先来看看它的起点——程序。

定义:程序是一个静态的文件,通常是经过编译链接后生成的可执行二进制文件(在 Linux 中,我们最熟悉的莫过于 ​
​a.out​
​)。特性:它就像一部写好了的剧本。剧本本身不发声、不动、不消耗舞台资源(CPU、内存),它只安安静静地躺在书架上(磁盘),占用一些存储空间。

【实验一:见证一个“剧本”的诞生】

让我们来编写并编译一个最简单的 C 语言程序。

代码 (
demo.c
​)



#include <stdio.h>
#include <unistd.h>
 
int main() {
    printf("I am a program, my destiny is to become a process.
");
    // sleep(10); // 暂时注释掉,下一节再用
    return 0;
}

编译与观察



# 1. 编译 C 代码,生成可执行文件 a.out
gcc demo.c
 
# 2. 查看文件详情
ls -l a.out
 
# 3. 查看文件类型
file a.out

运行结果



$ ls -l a.out
-rwxr-xr-x 1 user user 16696 Nov 20 10:30 a.out
 
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), ...

结果分析: ​
​ls​
​ 和 ​
​file​
​ 命令的结果明确告诉我们,​
​a.out​
​ 只是一个躺在磁盘上的、具有特定格式(ELF 64-bit)的可执行文件。此刻,它没有消耗任何 CPU 或内存,它就是一个静态的“剧本”。

二、 动态的“戏剧”:进程的登场

当操作系统加载并执行这个“剧本”时,**进程(Process)**就诞生了。

定义:进程是程序的一次动态执行过程特性:它是一场正在上演的戏剧。为了上演,它需要占用各种系统资源:

舞台(CPU):获得计算能力。场地和道具(内存):加载代码、数据,并拥有独立的虚拟地址空间。演员(各种数据):在舞台上活动。

【实验二:唤醒进程并观察它】

现在,我们让 ​
​demo.c​
​ 里的进程多活一会儿,以便我们能“抓住”它。

修改代码 (
demo.c
​)



#include <stdio.h>
#include <unistd.h>
 
int main() {
    printf("I am a process now! My PID is: %d
", getpid());
    printf("You have 20 seconds to find me using 'ps' command...
");
    sleep(20); // 让进程睡眠20秒,而不是立即退出
    printf("Time is up, I am exiting.
");
    return 0;
}

我们使用了 ​
​getpid()​
​ 来获取进程的唯一标识符(PID),并用 ​
​sleep(20)​
​ 让它持续运行20秒。

编译与运行

重新编译:​
​gcc demo.c -o demo​
在第一个终端运行:​
​./demo​
【关键】立即打开第二个终端,使用 ​
​ps​
​ 命令查找我们的进程。


ps aux | grep demo

运行结果

终端一:



I am a process now! My PID is: 23451
You have 20 seconds to find me using 'ps' command...
(光标在此处等待20秒)
Time is up, I am exiting.

终端二 (在20秒内执行):



$ ps aux | grep demo
user      23451  0.0  0.0   2388   860 pts/0    S+   10:35   0:00 ./demo
user      23453  0.0  0.0   6432   720 pts/1    S+   10:35   0:00 grep --color=auto demo

结果分析: ​
​ps​
​ 命令的结果抓到了一个活生生的进程!PID 为 ​
​23451​
​ 的 ​
​./demo​
​ 进程正在运行(状态 ​
​S+​
​ 表示在前台睡眠)。它占用了 CPU (0.0%) 和内存,拥有独立的进程ID。这证明,进程是程序运行时的动态实例。

一个剧本,多场戏剧 (1:N 关系) 如果我们在后台同时运行多个 ​
​./demo​
​ 实例呢?



./demo &
./demo &
ps aux | grep demo

你会发现,同一个 ​
​demo​
​ 程序,产生了多个拥有不同 PID 的进程。这完美诠释了程序和进程之间 1:N 的关系。

三、 并发之舞:单核 CPU 如何上演“多线程”大戏?

我们都知道,现在的操作系统可以“同时”听歌、写代码、聊微信。这种现象叫做并发(Concurrency)。但在一个单核 CPU 上,任意时刻真的只能做一件事。它是如何创造出“同时”运行的假象的呢?

答案是:时间片轮转(Time-Slicing)

单道程序设计:像古老的 DOS 系统,任务必须排队。听完歌才能看电影。CPU 在等待 I/O 时会完全闲置,效率极低。多道程序设计:现代操作系统将 CPU 时间切成极小的片段(毫秒甚至微秒级),称为时间片。它通过一个调度程序,飞快地在多个进程之间切换。

进程 A 运行一个时间片 -> 切换进程 B 运行一个时间片 -> 切换进程 C 运行一个时间片 -> 切换 -> 回到 A …

由于 CPU 的切换速度(纳秒级)远超人类的感知极限(毫秒级),在我们看来,所有进程就好像在并行执行。这就是**“宏观并行,微观串行”**。

【实验三:模拟并发的幻觉】

我们将编写一个程序,它有两个任务:打印 'A' 和打印 'B'。

代码 (
concurrency_sim.c
​)



#include <stdio.h>
#include <unistd.h>
 
// 任务A:持续打印 'A'
void task_a() {
    for (int i = 0; i < 20; i++) {
        printf("A");
        fflush(stdout); // 立即刷新缓冲区,强制输出
        usleep(100000); // 模拟耗时操作
    }
}
 
// 任务B:持续打印 'B'
void task_b() {
    for (int i = 0; i < 20; i++) {
        printf("B");
        fflush(stdout);
        usleep(100000);
    }
}
 
int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("--- Simulating Single-Tasking ---
");
        task_a();
        task_b();
        printf("
");
    } else {
        if (argv[1][0] == 'A') {
            task_a();
        } else if (argv[1][0] == 'B') {
            task_b();
        }
    }
    return 0;
}

编译与运行


gcc concurrency_sim.c -o sim

1. 模拟单道执行:


./sim

结果:



--- Simulating Single-Tasking ---
AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBB

分析:非常清晰,任务 A 必须完全结束后,任务 B 才能开始。这是典型的串行执行。

2. 模拟多道并发执行: 我们将启动两个进程,一个执行任务 A,一个执行任务 B,让操作系统来调度它们。



# 在后台启动任务A,然后立即在后台启动任务B
./sim A & ./sim B &
# 等待几秒钟让它们执行完毕

结果 (每次可能略有不同):


AABABBABABABBABABABA

分析:看到了吗?'A' 和 'B' 的输出被完美地交织在了一起!这并不是因为它们在“同时”运行,而是因为操作系统调度器在两个 ​
​./sim​
​ 进程之间进行了高速切换。我们亲手制造并观察到了并发的“幻觉”。

知识小结

概念

本质

状态

资源占用

关系

比喻

程序

二进制文件

静态

仅磁盘空间

1 : N

剧本

进程

运行中的程序实例

动态

CPU, 内存等

N : 1

戏剧

并发

宏观并行,微观串行

动态切换

CPU时间片

多进程共享

多场戏剧在同一舞台上分时上演

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容