process (进程) & thread (线程)

创建时间:
2017-03-17 00:36
最近更新:
2018-06-11 09:42

相关

  • 同步 (lock) - 详见本站专文
  • 异步 / 并发 / 多线程 - 详见本站专文
  • System.Threading 命名空间 (进程、线程) - 详见本站专文

Resource - MSDN

  1. System.Diagnostics 命名空间 - 该命名空间提供特定的类,使您能够与系统进程、事件日志和性能计数器进行交互。还提供用于调试应用程序和跟踪代码执行情况的类。
  2. System.Diagnostics.Process 类 - 提供对本地和远程进程的访问并使您能够启动和停止本地系统进程

Resource

  1. 为什么 windows 应用善于用线程,而 unix 用进程? 例如 oracle、httpd,他们在 windows 上用线程,unix 用进程,unix 也有线程呀,为什么会有如此不同的设计实现?

Glossary

  • process 进程
  • thread 线程

thread - 金山词霸

n. 线;线索;线状物;螺纹
vt. 穿成串;将(针、线等)穿过…;用…线缝;给…装入(胶片、狭带、绳子)
网络: 线程; 线; 螺纹; 执行绪

Brief

  • 进程和线程不是编程语言的概念,是操作系统的概念。
  • 一个程序至少有一个进程,一个进程至少有一个线程。

网摘 《Windows 的进程和线程1 - 基本的概念 - 牛开放》

这篇文章用来对 Window 下的进程和线程的基本概念来做总结,文章的形式是采用问答式,这样可以更有目的性。

1、进程和线程分别是什么?

说道这个问题,我们需要首先说下操作系统,操作系统将硬件管理起来,提供统一管理接口供用户调用。操作系统提供一个平台,进程则在平台上完成相应的操作 (比如听音乐,看电影,编辑 Word 文档等等)。在现代的操作系统中,操作系统支持多进程,即现代操作系统支持多个进程 "同时" 运行。进程提供了运行的环境,具体的逻辑任务由线程来完成。

我们来系统总结下: 进程提供一个各种资源的容器,定义了一个地址空间作为基本的执行环境; 线程是一个指令执行序列,可以直接访问进程中的资源。每个进程中至少有一个线程,线程在任一时刻必属于某个进程。

2、前面说现代操作系统支持多个进程同时运行,那么是如何实现同时运行呢?

这里的同时运行,需要区分 CPU 多核和单核的情况。

在单核的情况下,因为只有一个 CPU,所以只能是在某一个时候只有一个进程在运行,操作系统采用了 "分时" 的办法。

首先,我们可以将进程想象为一长串顺序的指令流,当指令流执行完毕后,进程就退出来了,那么我们可以将这一串指令流来切开,即将这一长串指令流切为一片一片的指令片,只要 CPU 按照顺序执行这些指令片,也能得到和一直执行进程的结果。

当有多个进程的时候,我们将每个进程都切为对应的片,每隔一定时间来执行某个进程的片,之后在切换到另一个进程的片,这样就达到了 "同时运行" 的效果。只要时间片是很短暂的,小于人的感知时间 (大约 100ms 到 200ms),就可以让人感觉不到进程在切换。

多核的情况和单核的情况相似,也是采用 "分时" 的方法。只不过是多核有多个处理器。这里可以把每个核想象为一个个单核就可以了。

到这里,大家就知道了如何达到多进程并行的效果,那么这需要操作系统提供什么呢?

很显然,操作系统要想完成分时的效果,需要做如下的事情:
a. 维护一个全局的进程表,记录当前哪些进程正在被执行。
b. 将时间分为适当的片段。
c. 在进程间实施切换,即保存上一个进程的执行环境信息,恢复下一个进程的执行环境。

3、进程在操作系统中是怎么来的和怎么没的呢?

在操作系统启动的时候,需要先把进程的运行环境全部创建起来,为进程的运行打好基础。创建一个进程即为进程建立基本的执行环境,然后将其加入到系统的全局进程表中,这样进程就能获得相应的资源来运行。

而进程的退出则是通知操作系统将其由全局进程表中去除,之后销毁此进程所有的资源。一般,系统会有检测的功能,当发现某个进程不正常的时候,操作系统可以将这个进程 "杀掉",从而释放对应的资源。

4、既然进程就能达到并行的目的,那么为什么还需要线程呢?

总地说来,是因为线程比进程成本更低。因为创建一个进程需要为其分配各种资源,而线程只需要使用进程事先分配好的即可;进程之间的通信成本也会较高,而线程则是在一个进程的环境下,通信起来会很方便。其实,我们可以把线程看做是一个 "轻量级" 的进程。

5、线程的创建和切换是什么样子的?

线程的创建其实和进程类似,也是建立起来线程的执行环境,比如分配线程所需要的数据结构和调用栈,完成这些数据结构的初始化操作。虽然这些操作比较于进程是很轻量级的,但是频繁创建和销毁也会是不可忽视的消耗。所以当需要频繁创建和销毁线程的时候,可以考虑线程池式的方式来解决消耗过大的问题。

进程中的多个线程执行的时候,是乱序的,即在某个时刻执行哪个线程,是不确定的,所以多线程的问题会比较难以调试。对于线程来说,是有用户态和内核态的区别,当进行线程切换的时候,如果线程是用户态,是需要切换为内核态的,这种切换也是需要耗费资源,不过目前随着硬件的发展,这部分切换的成本正在减少,所以,这部分的开销是可以接受的,大部分情况下,我们可以忽略线程的切换。

6、线程的调度算法

在这里我们先需要来了解下如何评价算法。调度算法的准则大约有如下的方面:
a. 公平性,在选择下一个运行的线程时,要考虑同等地位的线程必须有相同的机会来获取处理器执行权。
b. CPU 有效利用,即只要有进程和线程在等待,CPU就不能空闲。

对于不同类型的操作系统会对算法有不同的需求,例如: 实时操作系统对于响应时间有最低的要求。

调度算法可以分为非抢占式和抢占式,在非抢占式系统中,一个线程一旦被选择在处理器上执行,就一直运行,直到阻塞或自愿放弃或退出。我们可以看到,这类算法如果一个线程陷入长时间的处理中时,系统就无法切换其它的线程,容易造成其它线程的饿死。而抢占式系统中,一个线程被选中后,允许运行的时间长度有最大的限制,当到达这个时间后,就被迫放弃执行权,由系统来决定下一个执行的线程。

这里介绍三种典型的线程调度算法,限于篇幅,这里只给出简单的介绍,具体了解则需要去寻找对应的资料。
a. 先到先服务算法:这是在非抢占系统中的算法,顾名思义,即谁先来先执行谁。
b. 时间片轮换算法:将处理器时间分为最大长度不超过某个时间的片段,然后用轮转的方式来分配给线程。
c. 优先级调度算法:将线程分为不同的优先级,之后按照优先级来调度算法。

7、Windows 线程采用了何种调度算法呢?

Windows 的调度算法是 抢占式,支持多处理器的优先级调度算法,即结合了前面几种算法的优缺点的一种算法。Windows 为每个处理器定义了一个链表数组,相同优先级的线程在同一链表中。当线程满足执行条件的时候,它首先被挂到当前处理器的一个待分配的链表 (延迟的就绪链表),然后调度器在适当的时候 (当调度器获取控制权) 把待分配表上的线程分配到到某个处理器对应优先级的线程链表中。当处理器选择下一个运行的线程时,会根据优先级来选择线程。

以上就是 Windows 进程和线程的简单总结了。如果有描述错误或不清楚的地方,请指正。

参考资料: 《Windows 内核原理与实现》 - 潘爱民

-- http://zhuanlan.zhihu.com/p/21328442

网摘

进程是 CPU 资源分配的最小单位,
线程是 CPU 调度的最小单位。
以前进程既是资源分配也是调度的最小单位,后来为了更合理的使用 CPU (实际上是 CPU 性能越来越好),才将资源分配和调度分开,就有了线程。
线程是建立在进程的基础上的一次程序运行单位。
-- http://www.zhihu.com/question/25532384/answer/95207331

CPU + RAM + 各种资源 (比如显卡、光驱、键盘、GPS、等等外设) 构成我们的计算机,但是计算机的运行,实际就是 CPU 和相关寄存器以及 RAM 之间的事情。

一个最最基础的事实: CPU 太快,太快,太快了,仅寄存器能够追的上它的脚步,RAM 和别的挂在各总线上的设备完全是望其项背。

当多个任务要执行的时候怎么办呢? 轮流着来? 或者谁优先级高谁来? 不管怎么样的策略,一句话: 在 CPU 看来就是轮流着来。

一个必须知道的事实: 执行一段程序代码,实现一个功能的过程。当得到 CPU 的时候,相关的资源 (显卡、GPS 等) 必须也已经就位,然后 CPU 开始执行。这里除了 CPU 以外所有的资源就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的 CPU 执行时间用完了,那它就要被切换出去,等待下一次 CPU 的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被 CPU 临幸的运行环境,必须保存。

串联起来的事实: 前面讲过在 CPU 看来所有的任务都是一个一个的轮流执行,具体的轮流方法就是 "先加载程序 A 的上下文,然后开始执行 A,保存程序 A 的上下文,调入下一个要执行的程序 B 的程序上下文,然后开始执行 B,保存程序 B 的上下文..."。

重要的东西出现了: 进程和线程就是在这样的背景下出来的,两个名词不过是对应的 CPU 时间段的描述。进程就是 "程序执行时间总和 = CPU 加载上下文 + CPU 执行 + CPU 保存上下文"。

线程是什么呢? 进程的颗粒度太大,每次都要有上下文的调入,保存,调出。如果我们把进程比喻为一个运行在计算机上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序 A,实际分成 a、b、c 等多个块组合而成。那么这里具体的执行就可能变成 "程序 A 得到 CPU,CPU 加载上下文,开始执行程序 A 的 a 小段,然后执行 A 的 b 小段,然后再执行 A 的 c 小段,最后 CPU 保存 A 的上下文。这里 a、b、c 的执行共享了 A 的上下文,CPU 在执行的时候没有进行上下文切换。这里的 a、b、c 就是线程,也就是说线程共享了进程的上下文环境,是更为细小的 CPU 时间段"。

总结: 进程和线程都是对时间段的描述,是对 CPU 工作时间段的描述,只是颗粒大小不同。

-- http://www.zhihu.com/question/25532384/answer/81152571