进程和线程之间的技术区别是什么?

我感觉像“进程”这样的词被过度使用了,而且还有硬件和软件线程。像Erlang这样的语言中的轻量级进程怎么样?是否有明确的理由使用一个术语而不是另一个术语?


当前回答

基本上,线程是进程的一部分,如果没有进程线程就无法工作。线程是轻量级的,而进程是重量级的。进程之间的通信需要一些时间,而线程需要更少的时间。线程可以共享同一个内存区域,而进程则单独存在。

其他回答

进程和线程都是独立的执行序列。典型的区别是(同一进程的)线程在共享内存空间中运行,而进程在单独的内存空间中。

我不确定你可能指的是什么“硬件”线程和“软件”线程。线程是一种操作环境特性,而不是CPU特性(尽管CPU通常具有使线程高效的操作)。

Erlang使用术语“进程”,因为它不公开共享内存多道程序模型。称它们为“线程”意味着它们共享内存。

我认为理解差异的最简单方法是可视化线程和进程如何执行它们的任务。


线程在共享内存空间(创建它们的进程)中并行运行:

Thread 1              Thread 2              Thread 3
   | 
   | 
   |
                         |
                         |
                                               |
                                               |
                                               |
   |
                         |
                         | 
                         |            
Complete             Complete              Complete

注意:以上可以解释为一个进程(即一个进程有3个线程)


进程并行并行运行:

Process 1              Process 2              Process 3
    |                      |                      |
    |                      |                      |
    |                      |                      |
    |                      |                      |
    |                      |                      |
    |                      |                      |
Complete               Complete               Complete

尝试从Linux内核的OS视图回答

程序在启动到内存中时成为一个进程。进程有自己的地址空间,这意味着在内存中有各种段,例如用于存储编译代码的.text segment,用于存储未初始化的静态或全局变量的.bss等。每个进程都有自己的程序计数器和用户空间堆栈。在内核内部,每个进程都有自己的内核堆栈(由于安全问题,它与用户空间堆栈分离)和一个名为task_struct的结构,该结构通常被抽象为进程控制块,存储有关进程的所有信息,例如其优先级、状态(以及大量其他块)。一个进程可以有多个执行线程。

对于线程,它们驻留在一个进程内,并与线程创建过程中可以传递的其他资源(如文件系统资源、共享挂起的信号、共享数据(变量和指令))共享父进程的地址空间,从而使线程轻量级,从而允许更快的上下文切换。在内核内部,每个线程都有自己的内核堆栈以及定义线程的task_struct结构。因此,内核将同一进程的线程视为不同的实体,并且它们本身是可调度的。同一进程中的线程共享一个称为线程组id(tgid)的公共id,它们也有一个名为进程id(pid)的唯一id。

首先,让我们看看理论方面。您需要从概念上理解什么是进程,才能理解进程和线程之间的区别以及它们之间的共享。

Tanenbaum在第2.2.2节现代操作系统的经典线程模型3e中介绍了以下内容:

流程模型基于两个独立的概念:资源分组和执行。有时将它们分开是有用的;这是线程进入的地方。。。。

他继续说道:

看待过程的一种方式是将相关资源分组在一起。进程具有地址空间包含程序文本和数据以及其他资源。这些资源可以包括打开的文件、子进程、挂起的警报等,信号处理器、会计信息等。通过将它们以流程的形式结合在一起,可以更容易地管理它们。进程的另一个概念是执行线程,通常缩短为仅螺纹。线程有一个程序计数器跟踪下一步要执行的指令。它有寄存器保持其当前工作变量。它有一个堆栈,其中包含执行历史,每个过程调用一帧,但未调用但从返回。尽管线程必须在某些进程中执行线程及其进程是不同的概念分别地。流程用于将资源分组在一起;螺纹是计划在CPU上执行的实体。

接下来,他提供了下表:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

让我们来处理硬件多线程问题。传统上,CPU将支持单个执行线程,通过单个程序计数器(PC)和一组寄存器来维护线程的状态。但当缓存未命中时会发生什么?从主内存中获取数据需要很长时间,而当这发生时,CPU只是闲置在那里。所以有人想到了基本上有两组线程状态(PC+寄存器),这样另一个线程(可能在同一个进程中,也可能在不同的进程中)就可以在其他线程等待主内存时完成工作。这个概念有多种名称和实现,例如超线程和同时多线程(简称SMT)。

现在让我们看看软件方面。基本上有三种方法可以在软件端实现线程。

用户空间线程内核进程两者的结合

实现线程所需要的是保存CPU状态和维护多个堆栈的能力,这在许多情况下可以在用户空间中完成。用户空间线程的优点是超快速的线程切换,因为您不必陷入内核,也不必按照自己喜欢的方式调度线程。最大的缺点是无法阻止I/O(这会阻止整个进程及其所有用户线程),这是我们首先使用线程的主要原因之一。在许多情况下,使用线程阻止I/O大大简化了程序设计。

除了将所有调度问题留给操作系统之外,内核线程还具有能够使用阻塞I/O的优点。但每个线程切换都需要捕获内核,这可能会相对较慢。然而,如果由于I/O阻塞而切换线程,这实际上不是问题,因为I/O操作可能已经将您困在内核中。

另一种方法是将两者结合起来,多个内核线程每个都有多个用户线程。

因此,回到术语问题,您可以看到流程和执行线程是两个不同的概念,您选择使用哪个术语取决于您所谈论的内容。关于“轻量级过程”这一术语,我个人看不出其中的意义,因为它并没有像“执行线程”这一词那样真正传达出正在发生的事情。

对于那些更喜欢通过可视化学习的人来说,这里是我创建的一个方便的图表,用于解释流程和线程。我使用了MSDN中的信息-关于进程和线程