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

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

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

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

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

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

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


当前回答

线程共享数据和代码,而进程不共享。栈不是为两者共享的。

进程也可以共享内存,更精确的代码,例如Fork()之后,但这是一个实现细节和(操作系统)优化。由多个进程共享的代码将(希望)在第一次写入代码时复制—这被称为写时复制。我不确定线程代码的确切语义,但我假设是共享代码。

           Process   Thread

   Stack   private   private
   Data    private   shared
   Code    private1  shared2

代码在逻辑上是私有的,但出于性能原因可能会被共享。 我不能百分之百肯定。

其他回答

在进程中,所有线程共享系统资源,如堆内存等,而线程有自己的堆栈

所以你的ans应该是一个进程中所有线程共享的堆内存。

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

Besides global memory, threads also share a number of other attributes (i.e., these attributes are global to a process, rather than specific to a thread). These attributes include the following: process ID and parent process ID; process group ID and session ID; controlling terminal; process credentials (user and group IDs); open file descriptors; record locks created using fcntl(); signal dispositions; file system–related information: umask, current working directory, and root directory; interval timers (setitimer()) and POSIX timers (timer_create()); System V semaphore undo (semadj) values (Section 47.8); resource limits; CPU time consumed (as returned by times()); resources consumed (as returned by getrusage()); and nice value (set by setpriority() and nice()). Among the attributes that are distinct for each thread are the following: thread ID (Section 29.5); signal mask; thread-specific data (Section 31.3); alternate signal stack (sigaltstack()); the errno variable; floating-point environment (see fenv(3)); realtime scheduling policy and priority (Sections 35.2 and 35.3); CPU affinity (Linux-specific, described in Section 35.4); capabilities (Linux-specific, described in Chapter 39); and stack (local variables and function call linkage information).

摘自:《Linux编程接口:Linux和UNIX系统编程手册》,Michael Kerrisk,第619页

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中的哪一个在线程之间共享。堆管理是另一回事——它只是对操作系统的一系列调用。但是如果你根本没有操作系统,比如在嵌入式系统中,你还能在你的代码中新建/删除吗?

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

来自维基百科(我认为这对面试官来说是个很好的回答:P)

Threads differ from traditional multitasking operating system processes in that: processes are typically independent, while threads exist as subsets of a process processes carry considerable state information, whereas multiple threads within a process share state as well as memory and other resources processes have separate address spaces, whereas threads share their address space processes interact only through system-provided inter-process communication mechanisms. Context switching between threads in the same process is typically faster than context switching between processes.