最近,我在一次采访中被问到一个问题:进程和线程有什么区别?真的,我不知道答案。我想了一会儿,给出了一个非常奇怪的答案。

线程共享相同的内存,而进程不共享。回答完这个问题后,面试官对我邪恶地笑了笑,然后接连问了我几个问题:

问:你知道节目分成哪些部分吗?

我的答案是:是的(认为这很简单)堆栈,数据,代码,堆

问:那么,告诉我:线程共享哪些片段?

我无法回答这个问题,最后只能把它们都说了出来。

请问,谁能就进程和线程之间的区别给出正确的、令人印象深刻的答案?


当前回答

真正需要指出的是,这个问题有两个方面——理论方面和实现方面。

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

我们从Tanenbaum的2.2.2节现代操作系统3e中的经典线程模型中获得以下内容:

流程模型基于两个独立的概念:资源 分组和执行。有时把它们分开是有用的; 这就是线程....的由来

他继续说:

One way of looking at a process is that it is a way to group related resources together. A process has an address space containing program text and data, as well as other resources. These resource may include open files, child processes, pending alarms, signal handlers, accounting information, and more. By putting them together in the form of a process, they can be managed more easily. The other concept a process has is a thread of execution, usually shortened to just thread. The thread has a program counter that keeps track of which instruc­tion to execute next. It has registers, which hold its current working variables. It has a stack, which contains the execution history, with one frame for each proce­dure called but not yet returned from. Although a thread must execute in some process, the thread and its process are different concepts and can be treated sepa­rately. Processes are used to group resources together; threads are the entities scheduled for execution on the 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        |

以上就是线程工作所需要的。正如其他人指出的那样,像段这样的东西是依赖于操作系统的实现细节的。

其他回答

真正需要指出的是,这个问题有两个方面——理论方面和实现方面。

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

我们从Tanenbaum的2.2.2节现代操作系统3e中的经典线程模型中获得以下内容:

流程模型基于两个独立的概念:资源 分组和执行。有时把它们分开是有用的; 这就是线程....的由来

他继续说:

One way of looking at a process is that it is a way to group related resources together. A process has an address space containing program text and data, as well as other resources. These resource may include open files, child processes, pending alarms, signal handlers, accounting information, and more. By putting them together in the form of a process, they can be managed more easily. The other concept a process has is a thread of execution, usually shortened to just thread. The thread has a program counter that keeps track of which instruc­tion to execute next. It has registers, which hold its current working variables. It has a stack, which contains the execution history, with one frame for each proce­dure called but not yet returned from. Although a thread must execute in some process, the thread and its process are different concepts and can be treated sepa­rately. Processes are used to group resources together; threads are the entities scheduled for execution on the 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        |

以上就是线程工作所需要的。正如其他人指出的那样,像段这样的东西是依赖于操作系统的实现细节的。

您说得很对,但是线程共享除堆栈之外的所有段。线程有独立的调用堆栈,但是其他线程堆栈中的内存仍然是可访问的,理论上你可以在其他线程的本地堆栈框架中保存内存指针(尽管你可能应该找到一个更好的地方来放置内存!)。

线程共享代码、数据段和堆,但不共享堆栈。

In an x86 framework, one can divide as many segments (up to 2^16-1). The ASM directives SEGMENT/ENDS allows this, and the operators SEG and OFFSET allows initialization of segment registers. CS:IP are usually initialized by the loader, but for DS, ES, SS the application is responsible with initialization. Many environments allow the so-called "simplified segment definitions" like .code, .data, .bss, .stack etc. and, depending also on the "memory model" (small, large, compact etc.) the loader initializes segment registers accordingly. Usually .data, .bss, .stack and other usual segments (I haven't done this since 20 years so I don't remember all) are grouped in one single group - that is why usually DS, ES and SS points to teh same area, but this is only to simplify things.

一般来说,所有段寄存器在运行时都可以有不同的值。 所以,面试的问题是正确的:CODE、DATA和STACK中的哪一个在线程之间共享。堆管理是另一回事——它只是对操作系统的一系列调用。但是如果你根本没有操作系统,比如在嵌入式系统中,你还能在你的代码中新建/删除吗?

我给年轻人的建议是——读一些好的汇编编程书。似乎大学的课程在这方面相当贫乏。

通常,线程被称为轻量级进程。如果我们把内存分成三个部分,那么它将是:代码,数据和堆栈。 每个进程都有自己的代码、数据和堆栈部分,由于这种上下文切换时间有点高。为了减少上下文切换的时间,人们提出了线程的概念,它与其他线程/进程共享数据和代码段,并拥有自己的堆栈段。