什么是进程和线程?
是的,我已经阅读了许多与操作系统相关的资料。 而我仍然在阅读。 但是,似乎他们都是以“抽象”的方式来描述过程和线索,这使得他们的行为和逻辑组织得到了很多高层次的阐述。 我想知道他们身体是什么? 在我看来,它们只是内核代码中维护和使用的一些内存“数据结构”,以方便程序的执行。 例如,操作系统使用一些过程数据结构(PCB)来描述为某个程序分配的过程的方面,例如其优先级,地址空间等等。 这样好吗?
通常,当你运行像notepad.exe这样的可执行文件时,这会创build一个进程。 这些进程可能会产生其他进程,但是在大多数情况下,您运行的每个可执行文件都有一个进程。 在这个过程中,可以有很multithreading。 通常首先有一个线程,通常从main
function的程序“入口点”开始。 指令是一个接一个地执行的,就像一个只有一只手的人一样,一个线程每次只能做一件事,然后才能进入下一个。
那第一个线程可以创build额外的线程。 每个附加的线程都有它自己的入口点,通常用一个函数定义。 这个过程就像一个容器,用于所有在其中产生的线程。
这是一个非常简单的解释。 我可以更详细地了解,但可能会与您在教科书中find的内容重叠。
编辑:你会注意到在我的解释中有很多“通常”的,因为有偶尔罕见的程序,做的事情截然不同。
为了理解进程和线程之间的区别,首先你需要知道的事实是, 进程不运行,线程可以 。
那么,什么是线程? 最近我可以解释它是一个执行状态 ,如:在CPU寄存器,堆栈,地段的组合。 你可以看到一个certificate,在任何时候打破debugging器。 你看到了什么? 一个调用堆栈,一组寄存器。 这是非常多的。 这是线程。
那么,现在什么是一个过程。 那么,它就像一个抽象的“容器”实体,用于运行线程。 就操作系统而言,第一个近似值是一个实体操作系统分配一些虚拟机,给一些系统资源分配(如文件句柄,networking套接字),&c。
他们如何一起工作? OS通过预留一些资源创build一个“进程”,并启动一个“主”线程。 那个线程可以产生更多的线程。 那些是一个过程中的线索。 他们或多或less都可以这样或那样的方式分享这些资源(比如,他们可能需要locking,以免损害别人的乐趣)。 从那里开始,操作系统通常负责维护VM内部的那些线程(检测和阻止访问不属于该进程的内存的尝试),提供某些types的线程调度,以便它们可以运行“一后另一个和 – 不只是一,所有的时间”。
以非抽象的方式描述线程和进程几乎是不可能的原因之一是它们是抽象的。
他们的具体实现有很大的不同。
比较一个Erlang进程和一个Windows进程:一个Erlang进程是非常轻量级的,通常less于400字节。 您可以在不太新的笔记本电脑上启动一千万个进程,而不会出现任何问题 他们很快就开始工作,他们很快就死了,你可以用它们来完成很短的任务。 每个Erlang进程都有它自己的垃圾收集器。 Erlang进程永远无法共享内存。
Windows进程非常繁重,有时候会有数百个MiBytes。 如果你幸运的话,你可以在一个健壮的服务器上启动几千个。 他们开始,死得很慢。 Windows进程是诸如IDE或文本编辑器或文字处理器等应用程序的单位,所以它们通常需要相当长的时间(至less几分钟)。 他们有自己的地址空间,但没有垃圾收集器。 Windows进程可以共享内存,但默认情况下不会。
线程是一个类似的问题:在x86上的NPTL Linux线程可以小到4 KiByte和一些技巧,你可以在32位x86机器上启动800000+。 这台机器肯定可以使用数千,甚至数万个线程。 一个.NET CLR线程的最小大小约为1 MiByte,这意味着其中只有4000个会占用32位机器上的整个地址空间。 因此,虽然4000 NPTL Linux线程通常不是问题,但您甚至无法启动 4000个.NET CLR线程,因为在此之前您将耗尽内存。
OS进程和OS线程在不同的操作系统之间也是以不同的方式实现的。 主要的两种方法是:内核只知道进程。 线程是由一个用户空间库实现的,根本不需要任何有关内核的知识。 在这种情况下,还有两种方法:1:1(每个线程映射到一个内核进程)或m:n(m线程映射到n进程,通常m> n,通常n == #CPU)。 线程发明后,这是许多操作系统采取的早期方法。 然而,它通常被认为是低效率的,并且已经在第二种方法的几乎所有系统上被replace:线程在内核中被实现(至less部分),以便内核现在知道两个不同的实体,线程和进程。
第三条路线的一个操作系统是Linux。 在Linux中,线程既不在用户空间也不在内核中实现。 相反,内核提供了一个线程和一个进程(实际上还有更多的东西)的抽象,称为一个任务。 一个任务是一个内核调度实体,它带有一组标志,决定哪些资源与它的兄弟姐妹共享,哪些资源是私有的。
根据你如何设置这些标志,你得到一个线程(共享几乎所有东西)或一个进程(共享所有系统资源,如系统时钟,文件系统命名空间,networking命名空间,用户ID命名空间,进程ID命名空间,但不要共享地址空间)。 但是,你也可以得到一些其他非常有趣的东西。 你可以平凡地得到BSD风格的jail(基本上与Process相同的标志,但不共享文件系统或networking命名空间)。 或者你可以得到其他操作系统称为虚拟化容器或区域(如监狱,但不共享UID和PID命名空间和系统时钟)。 几年以前,通过一种名为KVM(内核虚拟机)的技术,你甚至可以获得一个完整的虚拟机(不分享,甚至不是处理器的Page Tables)。 [关于这一点很酷的是,你可以在内核中重新使用高度调优的成熟的任务调度器来处理所有这些事情。 Xen虚拟机经常诟病的一件事是调度器的性能不佳。 KVM开发人员比Xen有更优越的调度程序,最好的是他们甚至不必为它写一行代码!
所以,在Linux上,线程和进程的性能比Windows和其他许多系统上的性能要好得多,因为在Linux上,它们实际上是一样的。 这意味着使用模式是非常不同的:在Windows上,您通常根据自己的权重决定是使用线程还是进程:我可以负担得起一个进程,还是应该使用线程,即使我实际上不想共享州? 在Linux上(通常是Unix),你可以根据它们的语义来决定:我真的想共享状态吗?
Unix上的进程比在Windows上更轻的一个原因是不同的用法:在Unix上,进程是并发和function的基本单位。 如果你想使用并发,你可以使用多个进程。 如果您的应用程序可以分解成多个独立的部分,则可以使用多个进程。 每一个进程只做一件事, 只有一件事。 即使是一个简单的单行shell脚本,通常也涉及数十个或数百个进程。 应用程序通常由许多通常是短命的进程组成。
在Windows上,线程是并发的基本单位,COM组件或.NET对象是function的基本单位。 应用程序通常由一个长时间运行的进程组成。
同样,它们被用于非常不同的目的,并且具有非常不同的devise目标。 不是那个或那个更好或更糟,只是它们如此不同,以至于共同的特征只能被抽象地描述出来。
关于线程和进程,几乎所有可以说的事情是:
- 线程属于进程
- 线程比进程更轻
- 线程彼此共享大部分状态
- 进程共享的状态比线程less得多(特别是,除非特别要求,它们一般不共享内存)
我会这样说 :
一个进程有一个内存空间,打开的文件,…和一个或多个线程。
线程是可以由系统在处理器上调度的指令stream。
看看我以前在SO上给出的详细答案。 它提供了洞察玩具内核结构负责维护过程和线程…
希望这有助于,最好的问候,汤姆。
我们在这里已经多次讨论过这个问题。 也许你会在这里find一些有用的信息:
进程和线程之间有什么区别?
进程与线程
线程和进程
进程是执行程序时使用的一组资源的容器。
一个过程包括以下内容:
- 私有虚拟地址空间
- 一个程序。
- 句柄的列表。
- 访问令牌。
- 唯一的进程ID。
- 至less有一个线程。
- 指向父进程的指针,不pipe进程是否存在。
这就是说,一个进程可以包含多个线程。
进程本身可以分组到作业中,作为进程的容器并作为单个单元执行。
一个线程是Windows用来安排在CPU上执行指令的。 每个过程至less有一个。
我有几页在我的wiki上,你可以看看:
处理
线
物理:
-
进程是维护拥有的凭证,线程列表和打开的句柄列表的结构
-
线程是一个包含上下文 (即保存的寄存器集合+要执行的位置)的结构,描述哪些页面被映射到进程的虚拟地址空间中的一组PTE以及所有者。
这当然是一个非常简单的解释,但它却是重要的一点。 Linux和Windows的基本执行单位是线程 – 内核调度程序不关心进程(很多)。 这就是为什么在Linux上,一个线程只是一个碰巧与另一个进程共享PTE的进程。
进程是由OSpipe理的内存区域,用于运行应用程序。 线程是运行专用任务的进程中的内存中的一个小区域。
正如你所说,线程是操作系统调度程序中的内存结构。 线程指向内存中某些指令的开始,并在调度程序决定它们应该时处理这些指令。 线程正在执行时,硬件计时器将运行。 一旦达到所需的时间,将会调用一个中断。 之后,硬件将停止当前程序的执行,并将调用注册的中断处理程序函数,该函数将成为调度程序的一部分,以通知当前线程已完成执行。
如果这就是你所要求的,那么它们不是物理的string。 ;)
据我所知,操作系统内的几乎所有东西都只是数据。 现代操作系统依赖于一些硬件要求:虚拟内存地址转换,中断和内存保护(在启动过程中有很多模糊的硬件/软件魔法,但我对这个过程并不熟悉)。 一旦这些物理需求到位,其他的一切都取决于操作系统devise人员。 这一切都只是大量的数据。
给这个问题正义的简短答案很难。
而冒着这个可怕的错误和简化的风险,你可以说线程和进程是一个操作系统/平台的概念; 和引擎盖下,你可以定义一个单线程的过程,
- 低级CPU指令(也就是程序)。
- 执行状态 – 含义指令指针(实际上是一个特殊的寄存器),寄存器值和堆栈
- 堆(又名通用存储器)。
在现代操作系统中,每个进程都有自己的内存空间。 除了共享内存(只有一些OS支持这个)操作系统在另一个内存空间禁止一个进程写入。 在Windows中,如果进程尝试,则会看到一般保护错误。
所以你可以说一个multithreading的过程就是整个包。 而每个线程基本上只不过是执行状态。
所以当一个线程被另一个线程抢占时(比如,在一个单处理器系统上),原则上所有的操作系统都要保存线程的执行状态(不知道是否需要做任何特殊的处理堆栈)并加载另一个。
另一方面,抢占整个过程的代价更高,可以想象。
编辑:这个想法也适用于Java这样的抽象平台。
我看到了很多答案,但是其中大部分对于初学者来说还不够清楚。
在任何现代操作系统中,一个进程都有一个虚拟CPU,虚拟内存,虚拟I / O。
虚拟CPU:如果您有多个内核,则可以为该进程分配一个或多个内核以供调度程序处理。
虚拟I / O:I / O可能在各个进程之间共享。 就像一个可以被多个进程共享的键盘一样。 所以,当你input一个记事本时,你会看到文本正在改变,而一个作为守护进程运行的密钥logging器正在存储所有的击键。 所以这个过程是共享一个I / O资源。
虚拟内存: http : //en.wikipedia.org/wiki/Virtual_memory你可以通过链接。
所以当一个进程从调度器的执行状态中退出时,它的状态包含存储在寄存器中的值,它的堆栈和堆以及更多的信息被保存到一个数据结构中。
所以现在当我们比较一个进程和一个线程时,一个进程启动的线程共享分配给启动它的进程的虚拟I / O和虚拟内存,而不是虚拟CPU。 所以可能有一个进程启动的多个线程都共享相同的虚拟内存和虚拟I / O bu但具有不同的虚拟CPU。
因此,当虚拟内存空间在进程的线程之间共享时,您理解需要将进程的资源locking为静态分配(堆栈)或dynamic分配(堆)。
同样,每个拥有自己的虚拟CPU的线程可以在不同的内核中并行运行,并显着减less进程的完成时间(只有明智地pipe理内存并且有多个内核,才能观察到减less)。
线程由进程控制,进程由操作系统控制
进程之间不共享内存 – 因为它在所谓的“受保护的平面模型”中工作,另一方面线程共享相同的内存。
使用Windows时,至less一次通过Win 3.1时,操作系统(OS)包含多个进程,每个进程都有自己的内存空间,不能在没有操作系统的情况下与其他进程交互。
每个进程都有一个或多个共享相同内存空间的线程,不需要操作系统与其他线程交互。
进程是一个线程的容器。
那么,我还没有看到“他们身体是什么”的答案。 所以我试试看
进程和线程是没有什么物理的。 它们是操作系统的一个function。 通常电脑的任何物理组件都不知道它们。 CPU只处理连续的操作码stream。 这些操作码可能属于一个线程。 然后操作系统使用陷阱和中断重新获得控制权,决定哪些代码优先,并切换到另一个线程。
进程和线程是抽象的 – 对于他们来说没有任何物理的东西,或者操作系统的任何其他部分。 这就是为什么我们称之为软件。
如果你用物理的angular度来看电脑,最终会遇到一堆模拟图灵机的电子设备。 试图用一台原始的Truing Machine做任何有用的事情,会在五分钟内把你的大脑变成Jell-O。 为了避免这种不愉快的经历,计算机人员开发了一系列抽象来分割计算的各个方面。 这使您可以专注于您感兴趣的抽象级别,而不必担心所有其他支持它的东西。 有些东西已经被投入电路(例如加法器之类),这使得它们是物理的,但绝大多数与我们合作的是基于一组抽象的。 作为一般规则,我们使用的抽象具有某种forms的math基础。 这就是为什么堆栈,队列和“状态”在计算中扮演如此重要的angular色 – 围绕这些抽象有一个充分的math基础,让我们build立和推理他们的操作。
关键在于认识到软件总是基于抽象的“事物”模型的组合。 这些“事物”并不总是与任何物质有关,更可能与其他抽象有关。 这就是为什么你无法在课本中的任何地方find令人满意的“物理”基础。
其他几个人已经发布了关于线程和进程的链接和解释,但是没有一个指向任何“物理”的东西。 正如你猜测的那样,它们实际上只是一组数据结构和规则,它们存在于操作系统的更大范围内(反过来,它们只是更多的数据结构和规则)
软件就像一个洋葱,层层叠叠,一旦你把所有的层(抽象)都剥离了,没有什么可以留下的! 但洋葱还是很真实的
进程是一个完整的实体,如exe文件或一个jvm。 可以有一个父进程的subprocess的exe文件再次运行在一个单独的空间。 线程是一个独立的执行path,在进程正在控制执行哪个线程,暂停等的同一个进程中。
他们只是抽象地提到的原因是他们是概念,而他们将作为数据结构来实现,没有普遍的规则是如何实现的。
这对线程/进程来说至less是真的,如果没有调度器和中断计时器,他们不会做很多事情。
调度器是操作系统select下一个线程运行一段有限时间的algorithm,中断计时器是一个周期性中断当前线程执行并将其控制callback度器的硬件。
忘记了一些事情:如果只有协作式线程,上面的情况就不是这样,合作式线程必须积极地控制下一个线程,如果一个线程轮询了另一个线程的结果,就等于第一个线程产生了结果。
它们比其他线程更轻量级,因为它们不需要底层操作系统的支持。
试图回答这个有关Java世界的问题。
一个进程是一个程序的执行,但一个线程是进程内的一个执行序列。 一个进程可以包含多个线程。 线程有时被称为轻量级进程 。
例如:
示例1:JVM在单个进程中运行,JVM中的线程共享属于该进程的堆。 这就是为什么几个线程可以访问同一个对象。 线程共享堆并有自己的堆栈空间。 这是一个线程如何调用一个方法和它的局部variables保持线程安全的从其他线程。 但是堆不是线程安全的并且为了线程安全必须被同步。
示例2:程序可能无法通过读取按键来绘制图片。 程序一定要充分注意键盘的input,缺乏一次处理多个事件的能力会导致麻烦。 这个问题的理想解决scheme是同时执行一个程序的两个或多个部分。 线程允许我们这样做。 这里画画是一个过程,阅读击键是子过程(线程)。