Recently, I have been asked a question in an interview what's the difference between a process and a thread. Really, I did not know the answer. I thought for a minute and gave a very weird answer.
Threads share the same memory, processes do not. After answering this, the interviewer gave me an evil smile and fired the following questions at me:
Q. Do you know the segments in which a program gets divided?
My answer: yep (thought it was an easy one) Stack, Data, Code, Heap
Q. So, tell me: which segments do threads share?开发者_高级运维
I could not answer this and ended up in saying all of them.
Please, can anybody present the correct and impressive answers for the difference between a process and a thread?
You're pretty much correct, but threads share all segments except the stack. Threads have independent call stacks, however the memory in other thread stacks is still accessible and in theory you could hold a pointer to memory in some other thread's local stack frame (though you probably should find a better place to put that memory!).
Something that really needs to be pointed out is that there are really two aspects to this question - the theoretical aspect and the implementations aspect.
First, let's look at the theoretical aspect. You need to understand what a process is conceptually to understand the difference between a process and a thread and what's shared between them.
We have the following from section 2.2.2 The Classical Thread Model in Modern Operating Systems 3e by Tanenbaum:
The process model is based on two independent concepts: resource grouping and execution. Sometimes it is useful to separate them; this is where threads come in....
He continues:
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 instruction 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 procedure 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 separately. Processes are used to group resources together; threads are the entities scheduled for execution on the CPU.
Further down he provides the following table:
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 |
The above is what you need for threads to work. As others have pointed out, things like segments are OS dependant implementation details.
From Wikipedia (I think that would make a really good answer for the interviewer :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.
Tell the interviewer that it depends entirely on the implementation of the OS.
Take Windows x86 for example. There are only 2 segments [1], Code and Data. And they're both mapped to the whole 2GB (linear, user) address space. Base=0, Limit=2GB. They would've made one but x86 doesn't allow a segment to be both Read/Write and Execute. So they made two, and set CS to point to the code descriptor, and the rest (DS, ES, SS, etc) to point to the other [2]. But both point to the same stuff!
The person interviewing you had made a hidden assumption that he/she did not state, and that is a stupid trick to pull.
So regarding
Q. So tell me which segment thread share?
The segments are irrelevant to the question, at least on Windows. Threads share the whole address space. There is only 1 stack segment, SS, and it points to the exact same stuff that DS, ES, and CS do [2]. I.e. the whole bloody user space. 0-2GB. Of course, that doesn't mean threads only have 1 stack. Naturally each has its own stack, but x86 segments are not used for this purpose.
Maybe *nix does something different. Who knows. The premise the question was based on was broken.
- At least for user space.
- From
ntsd notepad
:cs=001b ss=0023 ds=0023 es=0023
A process has code, data, heap and stack segments. Now, the Instruction Pointer (IP) of a thread OR threads points to the code segment of the process. The data and heap segments are shared by all the threads. Now what about the stack area? What is actually the stack area? Its an area created by the process just for its thread to use... because stacks can be used in a much faster way than heaps etc. The stack area of the process is divided among threads, i.e. if there are 3 threads, then the stack area of the process is divided into 3 parts and each is given to the 3 threads. In other words, when we say that each thread has its own stack, that stack is actually a part of the process stack area allocated to each thread. When a thread finishes its execution, the stack of the thread is reclaimed by the process. In fact, not only the stack of a process is divided among threads, but all the set of registers that a thread uses like SP, PC and state registers are the registers of the process. So when it comes to sharing, the code, data and heap areas are shared, while the stack area is just divided among threads.
Generally, Threads are called light weight process. If we divide memory into three sections then it will be: Code, data and Stack. Every process has its own code, data and stack sections and due to this context switch time is a little high. To reduce context switching time, people have come up with concept of thread, which shares Data and code segment with other thread/process and it has its own STACK segment.
Threads share the code and data segments and the heap, but they don't share the stack.
Threads share data and code while processes do not. The stack is not shared for both.
Processes can also share memory, more precisely code, for example after a Fork()
, but this is an implementation detail and (operating system) optimization. Code shared by multiple processes will (hopefully) become duplicated on the first write to the code - this is known as copy-on-write. I am not sure about the exact semantics for the code of threads, but I assume shared code.
Process Thread Stack private private Data private shared Code private1 shared2
1 The code is logically private but might be shared for performance reasons. 2 I am not 100% sure.
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()
andnice()
).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).
Excerpt From: The Linux Programming Interface: A Linux and UNIX System Programming Handbook , Michael Kerrisk, page 619
Threads share everything [1]. There is one address space for the whole process.
Each thread has its own stack and registers, but all threads' stacks are visible in the shared address space.
If one thread allocates some object on its stack, and sends the address to another thread, they'll both have equal access to that object.
Actually, I just noticed a broader issue: I think you're confusing two uses of the word segment.
The file format for an executable (eg, ELF) has distinct sections in it, which may be referred to as segments, containing compiled code (text), initialized data, linker symbols, debug info, etc. There are no heap or stack segments here, since those are runtime-only constructs.
These binary file segments may be mapped into the process address space seperately, with different permissions (eg, read-only executable for code/text, and copy-on-write non-executable for initialized data).
Areas of this address space are used for different purposes, like heap allocation and thread stacks, by convention (enforced by your language runtime libraries). It is all just memory though, and probably not segmented unless you're running in virtual 8086 mode. Each thread's stack is a chunk of memory allocated at thread creation time, with the current stack top address stored in a stack pointer register, and each thread keeps its own stack pointer along with its other registers.
[1] OK, I know: signal masks, TSS/TSD etc. The address space, including all its mapped program segments, are still shared though.
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.
In general, all segment registers can have different values upon run-time. So, the interview question was right: which one of the CODE, DATA, and STACK are shared between threads. Heap management is something else - it is simply a sequence of calls to the OS. But what if you don't have an OS at all, like in an embedded system - can you still have new/delete in your code?
My advice to the young people - read some good assembly programming book. It seems that university curriculae are quite poor in this respect.
Thread share the heap (there is a research about thread specific heap) but current implementation share the heap. (and of course the code)
In process all threads share system resource like heap Memory etc. while Thread has its own stack
So your ans should be heap memory which all threads share for a process.
精彩评论