最近在面试中被问到一个问题,进程和线程的区别是什么。实际上我并不知道答案,思考了一会儿后给出了一个非常奇怪的回答:
线程共享内存,进程不共享。回答完这个问题后,面试官冷笑着向我提出了下面的问题:
问:你知道程序被分成哪些段吗?
我的回答:当然(认为这是一个简单的问题)栈、数据、代码、堆。
问:那么,告诉我,线程共享哪些段?
我无法回答这个问题,最终只好说共享所有部分。
请问有谁能够正确而且令人印象深刻地解释进程和线程之间的区别呢?
最近在面试中被问到一个问题,进程和线程的区别是什么。实际上我并不知道答案,思考了一会儿后给出了一个非常奇怪的回答:
线程共享内存,进程不共享。回答完这个问题后,面试官冷笑着向我提出了下面的问题:
问:你知道程序被分成哪些段吗?
我的回答:当然(认为这是一个简单的问题)栈、数据、代码、堆。
问:那么,告诉我,线程共享哪些段?
我无法回答这个问题,最终只好说共享所有部分。
请问有谁能够正确而且令人印象深刻地解释进程和线程之间的区别呢?
你的理解基本正确,但线程共享所有段 除了 栈。线程有独立的调用栈,然而其他线程栈中的内存仍然是可访问的,并且理论上你可以保存一个指向另一个线程本地栈帧中的内存的指针(虽然你可能应该找一个更好的位置来放置该内存!)。
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 |
来自维基百科(我认为这将是面试官的很好答案:P)
线程与传统多任务操作系统进程的不同之处在于:
- 进程通常是独立的,而线程作为进程的子集存在。
- 进程携带大量状态信息,而进程内的多个线程共享状态、内存和其他资源。
- 进程有单独的地址空间,而线程共享它们的地址空间。
- 进程仅通过系统提供的进程间通信机制进行交互。
- 同一进程中的线程之间进行上下文切换通常比进程之间更快速。
ntsd notepad
: cs = 001b ss = 0023 ds = 0023 es = 0023
。一般来说,线程被称为轻量级进程。如果我们将内存分成三个部分,那么它们是:代码,数据和堆栈。 每个进程都有自己的代码、数据和堆栈部分,因此上下文切换时间稍长。为了减少上下文切换时间,人们提出了线程的概念,它与其他线程/进程共享数据和代码段,并拥有自己的堆栈段。
线程共享代码段、数据段和堆,但是它们不共享栈。
Fork()
之后,但这是一种实现细节和(操作系统)优化。被多个进程共享的代码将在第一次写入代码时复制 - 这称为写时复制。我不确定线程代码的确切语义,但我认为是共享的代码。选自:《Linux编程接口》(第二版), Michael Kerrisk,第619页
线程共享所有[1]。整个进程只有一个地址空间。
每个线程都有自己的堆栈和寄存器,但是所有线程的堆栈在共享的地址空间中可见。
如果一个线程在其堆栈上分配了某个对象,并将地址发送给另一个线程,则它们两者都可以平等地访问该对象。
实际上,我刚注意到一个更广泛的问题:我认为你混淆了“段”这个词的两种用法。
可执行文件的文件格式(例如ELF)其中包含不同的部分,可能被称为段,包含已编译的代码(文本),初始化数据,链接器符号,调试信息等。这里没有堆或栈段,因为那些只是运行时构造。
这些二进制文件段可以单独映射到进程地址空间中,具有不同的权限(例如,只读可执行代码/文本,以及复制写入非可执行初始化数据)。
按约定(由语言运行时库强制执行),此地址空间的区域用于不同的目的,例如堆分配和线程堆栈。这仅仅是内存,除非您正在虚拟8086模式下运行,否则可能不会分段。每个线程的堆栈是在线程创建时分配的一块内存,当前堆栈顶部地址存储在堆栈指针寄存器中,每个线程都保持其自己的堆栈指针以及其他寄存器。
[1]好吧,我知道:信号掩码、TSS/TSD等。包括所有映射的程序段在内的地址空间仍然是共享的。