五分钟让你深刻理解进程

五分钟让你深刻理解进程

作者:harryshayne    撰写日期:2011.10.29

 

一、什么是程序?什么是进程?什么是线程?

       首先先回顾一下经典的定义。程序(program)是为实现特定目标或解决特定问题而用计算机语言编写的命令序列的集合。进程(process)是一个执行中的程序的一个实例。线程(thread)是"进程"中某个单一顺序的控制流。

       接下来通过两个生活中的实例来给出一个感性认识。第一个实例是拍电影的场景。程序就相当于一个剧本,事先写好的,而进程就相当于依照这个剧本来拍电影的整个过程,包括这个过程的环境,线程则是整部电影的各个小场景的拍摄过程,线程之间必须有个同步,就如同一部电影很多场景的拍摄的先后顺序要协调一下。大家想想,操作系统相当于电影整个过程中的哪个角色?

       另一个实例就是元旦舞会的举办。举办舞会也需要事先写好的策划书,然后按照策划书来举办舞会,整个舞会也有很多不同的小事情。程序就相当于策划书,进程就相当于舞会的整个过程,线程就相当于舞会中的不同的小事情。

       接下来让我们从初级程序员的角度来看看这些概念。程序不用说了,就是你用计算机语言编写的代码。进程对于程序来说,相当于一个容器,程序的运行就是把程序装入容器,然后操作系统根据程序的命令使得这个容器运转起来,期间还可能需要向容器中加入一些其他的东西(比如DLL等)来使得程序正常运行。当应用程序被运行两次时,前一个进程容器里的东西并不会被倒掉,系统会找一个新的进程容器来容纳它,重复上述的过程。程序的执行是为了完成某项任务,而完成这项任务可能有很多小步骤需要完成,如果这些小步骤可以并发执行,则可以把这些小步骤作为进程中的线程,线程就是进程这个大步骤中的不同的需要协调的小步骤。

       进程中有什么内容呢?它的虚拟地址空间布局是什么样的呢?



图 1 进程组成内容

图2 进程的用户地址空间布局

       应用程序的格式是什么样的呢?我们编写的代码和编译好的应用程度的对应关系是怎样的呢?

图3 ELF文件的格式

图4 代码和ELF格式应用程序的对应关系

进程的特征

       动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。

  并发性:任何进程都可以同其他进程一起并发执行

  独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

  异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

  结构特征:进程由程序、数据和进程控制块三部分组成。

       多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变

为什么要引入进程?

       从理论角度看,是对正在运行的程序过程的抽象。传统的程序本身是一组指令的集合,是一个静态的概念,无法描述程序在内存中的执行情况,即我们无法从程序的字面上看出它何时执行,何时停顿,也无法看出它与其它执行程序的关系,因此,程序这个静态概念已不能如实反映程序并发执行过程的特征。

       从实现角度看,进程是一种数据结构,目的在于清晰地刻划动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。

 

一个程序的生与死是怎样的过程呢?

       下面讲一个EXE格式的程序的具体运行过程。首先点击exe应用程序的图标,操作系统的shell进程(也就是explorer.exe桌面进程)就会监测到这一动作,它便查找注册表中应用程序的相关信息(如果是绿色版软件就不需要查找注册表),然后Explorer.exe以应用程序文件名调用CreateProcess函数来创建一个进程,CreateProcess函数做的工作就是创建进程内核对象(操作系统用它来管理进程的一个数据结构),创建进程的虚拟地址空间,初始化虚拟地址空间(也就是把exe文件代码,数据以及其他一些必须的DLL文件映射到这个空间,还记不记得进程相当于一个容器?),创建主线程(一个进程至少要有一个主线程才能运行,可以说进程只是充当一个容器的作用,而线程才是执行用户代码的载体。就像一个运作的企业,它只是提供一个大环境,真正做事的都是里面的人)。主线程获得CPU时间后(因为可能有很多程序同时执行,操作系统要切换进程,我们的进程才能获得CPU时间),接下来就是主线程要执行代码了,首先是找到主函数入口(当然之前要做一些运行库的初始化,因为代码中要调用这些库函数),然后开始执行代码咯(像windows程序的话就是先注册窗口类,然后创建窗口或者对话框,然后等待用户的点击或者输入,因为windows程序是基于消息的,你点击一下就会发消息给程序,程序就根据消息的不同来执行相应的代码,然后循环点击-响应这个过程)。最后当你点击关闭的时候,程序就会关闭窗口,退出消息循环的过程,然后做一些内存清理的工作(因为你运行的时候系统给你分配了很多资源啊,结束了肯定要退还啊),最后调用ExitProcess函数来销毁进程(销毁空间啊,内核对象啊等),然后程序的运行就终止了。

回顾一下:

1、Shell(Explorer.exe)调用CreateProcess函数激活exe 程序

2、系统创建一个进程内核对象,引用计数置为1

3、系统为进程创建一个4GB 的进程虚拟地址空间

4、PE 装载器把exe 的代码映射到地址空间,并查找ImportTable 引入相关的动态链接库(DLLs)

5、系统为进程创建一个主线程,线程得到CPU 后,把CS:IP指向.text节中的程序进入点(OEP),此处是一条JMP 指令,它跳到XXXCRTStartup函数处执行

6、这里完成c/c++运行期库的一些初始化设置,包括c++构造函数的调用全局变量,静态变量的初始化

7、调用WinMain/main函数,进入主函数

8、注册窗口类,创建窗口,显示窗口,更新窗口,进入消息循环

9、销毁窗口,退出消息循环,销毁进程,程序运行结束。

<think>嗯,用户想理解线程和进程的区别及联系,需要深入解析。首先,我得回忆一下操作系统的基本知识。进程和线程都是并发编程的核心概念,但容易混淆。进程是资源分配的单位,线程是CPU调度的单位,对吧?但具体怎么解释清楚呢? 用户可能已经知道一些基本概念,但需要更深入的分析。根据提供的引用,比如引用[3]提到线程在进程内部执行,共享地址空间,而进程有独立的资源。需要把这些点展开。 首先,进程的定义。每个进程有独立的内存空间,包括代码段、数据段、堆栈等。进程之间切换开销大,因为需要切换上下文。而线程属于同一个进程,共享内存,所以通信更方便,开销更小。这点很重要,是主要区别之一。 然后,资源分配方面。进程拥有独立的系统资源,如文件描述符、内存等,而线程共享进程的资源。但每个线程有自己的栈和寄存器。这点需要详细说明,避免用户混淆。 联系方面,线程不能独立存在,必须依附于进程。一个进程可以有多个线程,这些线程协同工作。多线程可以提高程序的并发性,比如在GUI应用中处理后台任务。 接下来要考虑用户可能的疑问,比如为什么使用线程而不是多进程?因为线程更轻量,创建和切换更快。但多进程更稳定,一个进程崩溃不会影响其他进程。这时候可以结合引用[4]中的Python多线程和多进程的例子,说明不同场景下的选择。 另外,用户提到的引用[1]和[2]分别来自Java和Python,可能需要跨语言的例子,但用户现在的问题比较通用,所以应该保持语言中立,但可以适当提及不同语言中的实现差异。 安全问题也很重要。多线程共享数据可能导致竞争条件,需要同步机制,如互斥锁。而进程间通信需要IPC机制,如管道、消息队列等。这也是区别的一部分。 用户可能需要实际应用的例子,比如Web服务器使用多线程处理请求,或者科学计算使用多进程利用多核CPU。这些例子能帮助理解不同场景的选择。 最后,总结区别和联系时要结构清晰,分点列出,确保用户能逐步理解。同时,生成的相关问题要引导用户深入思考,比如优缺点、如何选择、通信方式等。</think>### 线程与进程的深度解析 #### 一、**核心定义** 1. **进程(Process)** - 是操作系统进行**资源分配和调度**的基本单位,拥有独立的虚拟地址空间、代码段、数据段、堆栈、文件句柄等资源。 - 例如:运行中的浏览器、Python解释器都是一个进程。 2. **线程(Thread)** - 是**进程内的执行单元**,共享进程的资源(如内存、文件),但拥有独立的程序计数器、寄存器组和栈空间[^3]。 - 例如:浏览器中同时加载页面和下载文件的两个任务可能由不同线程处理。 --- #### 二、**区别与联系** | **特性** | **进程** | **线程** | |-------------------|-----------------------------------|-----------------------------------| | **资源独立性** | 独立内存空间,资源隔离 | 共享进程内存,资源依赖性强 | | **切换开销** | 上下文切换成本高(需保存全部状态)| 切换成本低(仅需保存寄存器状态) | | **通信方式** | 需IPC机制(管道、共享内存等) | 可直接读写共享变量(需同步机制) | | **健壮性** | 崩溃不影响其他进程 | 一个线程崩溃可能导致整个进程终止 | | **创建/销毁速度** | 慢(需分配独立资源) | 快(复用进程资源) | **联系**: - 线程必须依附于进程存在,**进程是线程的容器**。 - 多线程共享进程资源,而多进程间资源完全隔离[^3][^4]。 --- #### 三、**应用场景对比** 1. **适合多进程的场景** - 需要高隔离性(如安全关键型任务) - 需充分利用多核CPU(如Python中规避GIL限制的科学计算[^4]) - 示例:分布式任务处理、独立服务部署。 2. **适合多线程的场景** - I/O密集型任务(如网络请求、文件读写) - 需要低延迟响应(如GUI界面的事件处理) - 示例:Web服务器处理并发请求[^1]。 --- #### 四、**代码示例(Python)** ```python # 多进程示例(独立内存空间) from multiprocessing import Process def task(): print("Process ID:", os.getpid()) if __name__ == "__main__": p = Process(target=task) p.start() p.join() # 多线程示例(共享内存) import threading counter = 0 lock = threading.Lock() def increment(): global counter with lock: counter += 1 threads = [threading.Thread(target=increment) for _ in range(100)] for t in threads: t.start() for t in threads: t.join() print("Final counter:", counter) # 输出100 ``` > 注:多线程需通过锁(Lock)解决竞态条件问题[^4]。 --- #### 五、**关键设计权衡** 1. **性能 vs 安全性** - 多线程性能高但需处理同步,多进程安全但开销大。 2. **资源利用率** - 线程适合资源共享,进程适合资源隔离[^3]。 3. **开发复杂度** - 多线程需处理死锁、数据竞争,多进程需设计通信协议。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值