计算机代写 Processes and Threads

Processes and Threads
Shuaiwen
USYD Future System Architecture Lab (FSA)
https://shuaiwen-leon-song.github.io/

Objectives
• To understand what a process is
• To learn the basics of exceptional control flow • Tolearnhowtocontrolchildprocesses
• Tolearnaboutotherprocessrelated functions
• Tolearnhowtoloadandexecuteprograms
• Tolearnaboutsignals
• Tolearnaboutpipes

› How does the operating system run programs?
How to run programs?
3

› How does the operating system run programs?
› Need abstraction of executing program
How to run programs?
4

› How does the operating system run programs?
› Need abstraction of executing program
› process = memory state + machine state
How to run programs?
5

Multi-Processing
The OS must handle multiple processes in execution at any given time…
How do we do this?

› An independent logical control flow that provides the illusion that our program has exclusive use of the processor
› A private address space that provides the illusion that our program has exclusive use of the memory system
What is a process?
7

›We need to identify process: › Get process id use getpid() function
How do we control process?
#include
#include
int main(int argc, char const *argv[])
{
printf(“pid = %d\n”, getpid());
return 0; }
8

›Need a way to create and destroy processes
How do we control process?
9

Create & Terminate Processes
A process is in one of three states
Running Stopped Terminated

Create & Terminate Processes
A process is in one of three states
Running Stopped Terminated
In the running state it is either executing on the CPU or
is waiting to be executed and eventually scheduled by the kernel

Create & Terminate Processes
A process is in one of three states
Running Stopped Terminated
In the stopped state the execution of the process is suspended and will not be scheduled. A process stops if it receives a SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU signal
(more on signals later)
More detailed POSIX signals refer to : https://en.wikipedia.org/wiki/Signal_(IPC)

Create & Terminate Processes
A process is in one of three states
Running Stopped Terminated
In the terminated state the process is stopped permanently. A process becomes terminated for one of three reasons: (1) receiving a signal to terminate, (2) returning from main, or (3) calling the exit function.

Create & Terminate Processes
A process is in one of three states
Running Stopped Terminated So, how do we create a running process?

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
fork() creates a new process.
It is almost identical to the parent – but, has a different PID. It gets a copy of the parent’s virtualaddress space, both heap and stack.

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
fork() returns different results to the parent and child: Parent gets the pid of the new child
Child gets 0 (so it can easily know it’s the child) -‐
if it needs its own pid it can simply call getpid to obtain it

Parent
Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
Child

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
Parent
Child

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”);
}
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”);
} else {
printf(“hello from parent\n”);
}
Parent
Child

Create & Terminate Processes
We use the fork() function to create a new process.
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
pid_t pid = fork(); if (pid == 0) {
printf(“hello from child\n”); } else {
printf(“hello from parent\n”); }
After forking, parent and child process share file descriptors but not virtual memory (although it gets a copy of the parent’s virtualaddress space, both heap and stack. )

Sharing Between Two Processes
› Can two processes share the same shared memory segment?
› Yes and no. Typically with modern operating systems, when another process is forked from the first, they share the same memory space with a copy-on- write set on all pages. Any updates made to any of the read-write memory pages causes a copy to be made for the page so there will be two copies and the memory page will no longer be shared between the parent and child process. This means that only read-only pages or pages that have not been written to will be shared.
› If a process has not been forked from another then they typically do not share any memory. One exception is if you are running two instances of the same program then they may share code and maybe even static data segments but no other pages will be shared.
22

Create & Terminate Processes
What does this print out?
void main() {
printf(“L0\n”); fork(); printf(“L1\n”); fork(); printf(“Bye\n”);
}
Bye L1 Bye
Bye L0 L1 Bye

Create & Terminate Processes
What does this print out?
Bye L2 Bye
Bye L1 L2 Bye Bye L2 Bye
Bye L0 L1 L2 Bye
Does it always print in order?
void main() {
printf(“L0\n”); fork(); printf(“L1\n”); fork(); printf(“L2\n”); fork(); printf(“Bye\n”);
}

Create & Terminate Processes
What does this print out?
How many lines of output will it produce?
A) 4 B) 5 C) 6 D) 7 E) 8
void main() {
printf(“L0\n”); if (fork() != 0) {
printf(“L1\n”); if (fork() != 0) {
printf(“L2\n”);
fork(); }
}
printf(“Bye\n”); }

Create & Terminate Processes
What does this print out?
void main() {
printf(“L0\n”); if (fork() != 0) {
printf(“L1\n”); if (fork() != 0) {
printf(“L2\n”);
fork(); }
}
printf(“Bye\n”); }
Bye
Bye
Bye L0 L1 L2 Bye

Create & Terminate Processes
What happens here?
void main() {
if (fork() == 0) {
/* Child */
printf(“Terminating Child, PID = %d\n”, getpid());
exit(0);
} else {
} }
printf(“Running Parent, PID = %d\n”, getpid());
while (1)
; /* Infinite loop */
Zombie!

Create & Terminate Processes
Linux
./main Running Parent, PID = 24753 Terminating Child, PID = 24754 kill -9 24754 ps
PID TTY 24721 pts/4 24753 pts/4
24755 pts/4
TIME CMD 00:00:00 bash 00:00:04 main
00:00:00 ps
24754 pts/4 00:00:00 main

Create & Terminate Processes
Linux
Zombie process cannot be killed, kill the parent process instead.

Create & Terminate Processes
What about this one?
void main() {
if (fork() == 0) {
/* Child */
printf(“Running Child, PID = %d\n”, getpid());
while (1)
; /* Infinite loop */
} else {
printf(“Terminating Parent, PID = %d\n”,
getpid());
exit(0);
} }
Zombie?

./main Terminating Parent, PID = 24950 Running Child, PID = 24951
:~/ctest$ ps -f
UID PID PPID C STIME TTY donglin 24911 24910 0 13:39 pts/5
donglin 24957 24911 0 13:40 pts/5
TIME CMD
00:00:00 -bash
00:00:00 ps -f
Create & Terminate Processes
donglin 24951 1 99 13:40 pts/5 00:00:27 ./main
Note: PPID=1, this is not a zombie (first process started on Linux at boot)

Need a way to get rid of(kill) the zombies!
This is called reaping!
How do we control processes?

Create & Terminate Processes
So, how do we “reap” a child process programmatically?
wait()
waitpid()
kill -s SIGCHLD pid
Zombie?

Create & Terminate Processes
int wait(int *child_status)
void main() {
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++) { fork a child processes if ((pid[i] = fork()) == 0) { // Child exit(100+i); }} for (i = 0; i < N; i++) { pid_t wpid = wait(&child_status); if (WIFEXITED(child_status)) { printf("Child %d terminated with exit status %d\n", } else { }}} wpid, WEXITSTATUS(child_status)); printf("Child %d terminated abnormally\n", wpid); Create & Terminate Processes int wait(int *child_status) void main() { pid_t pid[N]; int i; int child_status; for (i = 0; i < N; i++) { wait for each to terminate if ((pid[i] = fork()) == 0) { // Child exit(100+i); }} for(i=0;i=0;i–) {
pid_t wpid = waitpid(pid[i], &child_status, 0);
if (WIFEXITED(child_status)) {
printf(“Child %d terminated with exit status %d\n”,
} else { }}}
wpid, WEXITSTATUS(child_status)); printf(“Child %d terminated abnormally\n”, wpid);

int waitpid(-1, &status, 0)
is the same as…
int wait(&status)
Create & Terminate Processes

Activity
What is the output of the program on the left?
A. acbc
B. bcac
C. abcc
D. bacc
E. AorCorD
void main() {
if (fork() == 0) { printf(“a”);
}
else {
printf(“b”);
waitpid(-1, NULL, 0); }
printf(“c”);
exit(0); }

Activity
What is the output of the program on the left?
A. acbc
B. bcac
C. abcc
D. bacc
E. AorCorD
void main() {
if (fork() == 0) { printf(“a”);
}
else {
printf(“b”);
waitpid(-1, NULL, 0); }
printf(“c”);
exit(0); }

Putting a process to sleep: zzzzz…
› unsigned int sleep(unsigned int seconds);
#include void main()
{
int amt = sleep(5); }
Returns 0 if time has elapsed. Returns thenumberofsecondsleftto sleepifasignalwoke upthe
process.
41

› int pause(void);
Putting a process to sleep: zzzzz…
#include void main()
{
int amt = pause(); }
pause() returns only when a signal was caught and the signal-catching function returned. In this case, pause() returns -1
42

Loading and Running Programs
What does a shell program do?
vim
cd ps
emacs
A shell program is a special kind of program whose primary responsibility is to run otherprograms.
ls
43

Loading and Running Programs
int execve(const char* filename, const char* argv[],
const char* envp[]);
In computing, exec is a functionality of an operating system that runs an executable file in the context of an already existing process, replacing the previous executable. This act is also referred to as an overlay. It is especially important in Unix- like systems, although exists elsewhere. As a new process is not created, the process identifier (PID) does not change, but the machine code, data, heap, and stack of the process are replaced by those of the new program.
https://en.wikipedia.org/wiki/Exec_(system_call)

Loading and Running Programs
int execve(const char* filename, const char* argv[],
const char* envp[]);
We know what these are…

Loading and Running Programs
int execve(const char* filename, const char* argv[],
const char* envp[]); We know what these are…
But, what is this?

Loading and Running Programs
int execve(const char* filename, const char* argv[],
const char* envp[]); Every program runs in an “environment”. The environment
is customized using environment variables: PATH, EDITOR, … envp
envp[0]
envp[1]

envp[n-‐1]
NULL
“USER=richards”
“SHELL=/bin/bash”
“EDITOR=emacs”

Loading and Running Programs
int execve(const char* filename, const char* argv[],
const char* envp[]); It turns out that the more general form for main is:
int main(int argc,
const char* argv[],
const char* envp[]);

›Whereareargvandenvpin memorywhenaprocessexecutes?
Loading and Running Programs
49

Loading and Running Programs
Null-‐terminated environment variable strings
Null-‐terminatedcommand-‐lineargument strings
unused space
envp[n] == NULL
envp[n-‐1]

envp[0]
argv[argc] ==NULL
argv[argc-‐1]

argv[0]
(Dynamic Linker Variables)
envp
argv
argc
Stack frame for main
Bottom of stack
Where are argv and envp In memory when a process executes?
Topofstack
50

Loading and Running Programs
Null-‐terminated environment variable strings
Null-‐terminatedcommand-‐lineargument strings
unused space
envp[n] == NULL
envp[n-‐1]

envp[0]
argv[argc] ==NULL
argv[argc-‐1]

argv[0]
(Dynamic Linker Variables)
envp
argv
argc
Stack frame for main
Bottom of stack
Where are argv and envp In memory when a process executes?
So, how do we accessthe environment variables?
Topofstack
51

Loading and Running Programs
int* getenv(const char* name);
Returns pointer to value if there is an entry of the form “name=value”, and NULL if there is not
int setenv(const char* name, const char* newval,
int overwrite);
Returns 0 on success, -1 on error.
void unsetenv(const char* name);
Removing the name of the environmental variable. Upon successful completion, zero shall be returned. Otherwise, -1 shall be returned, errno set to indicate the error, and the environment shall be unchanged.

Signals
How do we communicate to processes?
We send them messages called signals
A signal is an event of some type that has occurred in the system.
It allows the OS to communicate to aprocess AND
user processes to communicate to eachother

Signals
How do we communicate to processes?
We send them messages called signals
If a process tries to divide by 0:
OS sends it a SIGFPE signal
If a process executes an illegal instruction:
OS sends it a SIGILL signal
A signal is an event of some type that has occurred in the system.
It allows the OS to communicate to aprocess AND
user processes to communicate to eachother
If a process makes illegal memory reference:
OS sends it a SIGSEGV signal

Signals
How do we communicate to processes?
We send them messages called signals
If you type ctrl-‐c:during processexec
OS sends it a SIGINT signal
A process can kill another process:
P1 sends P2 a SIGKILL signal
When a child terminates:
OS sends the parent a SIGCHLD signal
A signal is an event of some type that has occurred in the system.
It allows the OS to communicate to aprocess AND
user processes to communicate to eachother

Signals
How do we communicate to processes?
The transfer of a signal to a destination occurs in 2 steps
Sending a Signal Receiving a Signal

Signals
How do we communicate to processes?
Sending a Signal
The kernel sends a signal to a destination process by updating some state in the context of that process.
This occurs when the kernel detects a system event
(div by 0) or when a process invokes the kill system call to explicitly request the kernel to send a signal to the destination process.

› How do we communicate to processes? › Receiving a Signal
› A destination process receives a signal when it is forced by the kernel to react in some way.
› The process can either ignore the signal, terminate, or catch the signal by executing user‐level functions called signal handlers.
Signals

Signals
How do we communicate to processes?
• A signal is pending if sent but not yet received
– There can be at most 1 pending signal for a type
– Important: signals are not queued
• If a process has a pending signal of type k, then subsequent signals of type k that are sent to that process are discarded.
• A process can block the receipt of certain signals
– Blocked signals can be delivered, but will not be received until the signal is unblocked.

So, how are they implemented?
Process 1
Pending
Blocked
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0

So, how are they implemented?
Process 1
Pending
Blocked
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
0
0
0
0

0
Eachprocessstructurecontainsapendingandblockedbitvector. Each entry corresponds to a specific signal.

So, how are they implemented?
Process 1
Pending
Blocked
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
0

0
0
0
1
0

0
1
0
0
0

0
A process can decide to block a signal by setting the corresponding bit in the blocked bit vector.

So, how are they implemented?
Process 1
Pending
Blocked
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
0

0
0
0
1
0

0
1
0
0
0

0
Not all signals can be blocked:
SIGKILL can’t be blocked or handled by the process.

So, how are they implemented?
Process 1
Pending
Blocked
Kernel
SIGILL
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
0

0
0
0
1
0

0
1
0
0
0

0
Imagine the processor encounters an illegal instruction during the execution of Process 1

So, how are they implemented?
Process 1 Pending
SIGILL
Blocked
Kernel
SIGILL
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
1

0
0
0
1
0

0
1
0
0
0

0
The kernel will set the corresponding bit in the Pending bit vector

So, how are they implemented?
Process 1 Pending
SIGILL
Blocked
?
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
1

0
0
0
1
0

0
1
0
0
0

0
Just before Process 1 resumes execution the kernel will check to see if the process has any pending signals that are not blocked

So, how are they implemented?
Process 1 Pending
SIGILL
Blocked
?
Kernel
Process 2
Pending
Blocked
Signals
0
0
0
0

0
0
0
0
1

0
0
0
1
0

0
1
0
0
0

0
If it does it will check if the process has defined a signal handler for the signal or execute default behavior

Signals
So, how are they implemented?
Process 1 Pending
SIGILL
Blocked
Kernel
Process 2
Pending
Blocked
0
0
0
0

0
0
0
0
1

0
0
0
1
0

0
1
0
0
0

0
The default behavior for SIGILL is to terminate the process

So, how are they implemented?
Process 1 Pending
Blocked
Kernel
Process 2 Pending
Blocked
Signals
#include
int kill(pid_t pid, int sig);
0
0
0
0

0
0
0
0
0

0
0
0
1
0

0
1
0
0
0

0
A process can send another process a signal using the kill system call

So, how are they implemented?
Process 1 Pending
Blocked
Kernel
SIGINT
A process can send another process a signal using the kill system call
Process 2 Pending
Blocked
Signals
#include
int kill(pid_t pid, int sig);
0
0
0
0

0
0
0
0
0

1
0
0
1
0

0
1
0
0
0

0

So, how are they implemented?
Process 1 Pending
Blocked
Kernel
SIGINT
Signals
#include
int kill(pid_t pid, int sig);
Process 2 Pending
Blocked
0
0
0
0

0
0
0
0
0

1
0
0
1
0

0
1
0
0
0

0
Again, the kernel will check for pending signals, check for a handler or execute default behavior

Signals
#include
int kill(pid_t pid, int sig);
Process 2 Pending
Blocked
So, how are they implemented?
Process 1 Pending
Blocked
Kernel
SIGINT
0
0
0
0

0
0
0
0
0

1
0
0
1
0

0
1
0
0
0

0
Again, the kernel will check for pending signals, check for a handler or execute default behavior

We can send signals from the keyboard
ctrl-c
Typing ctrl-cfrom the keyboard sends a SIGINT signal to the shell.
The shell catches the signal and then sends a SIGINT to every process
in the foreground process group. ctrl-z
Typing ctrl-‐z from the keyboard sends a SIGTSTP signal to the shell.
The shell catches the signal and then sends a SIGTSTP to every process in the foreground process group.
Signals

Ok, so how do we send signals programmatically?
#include #include
int kill(pid_t pid, int sig);
Signals

And how do we catch a signal?
#include
unsigned int alarm(unsigned int secs);
Generates a SIGALRM signal to the Need a handler to “catch” the signal
Signals
calling process after secs seconds.
and do something interesting.

Register signal handler
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Signals
The signal
Sets the disposition of the signal signum to handler

Signals
#include
#include
#include
#include
void sig_alarm(int signal)
{
printf(“Receive alarm signal = %d\n”,
signal); }
int main(int argc, char *argv[])
{
signal(SIGALRM /*14*/, sig_alarm); alarm(1);
printf(“program end!\n”);
return 0;
}
Output:
Receive alarm signal = 14
program end!
Tell the OS to send a signal to a process with a certain delay.
77

Process Pros
• Clean Sharing Model
– Global variables (address spaces) are not shared – File tables (file descriptors) are shared
• Simple and straightforward
– Forking a child process is easy
– Reaping child processes is simple
– Processes are isolated for protection

• Forking a process is expensive
– Need to clone parent’s memory space
– Need to setup a separate context for child
Note: the concept of context switch and why it has high overhead: https://en.wikipedia.org/wiki/Context_switch#:~:text=In%20computing%2C%20 a%20context%20switch,of%20a%20multitasking%20operating%20system.
Process Cons

• Forking a process is expensive
– Need to clone parent’s memory space
– Need to setup a separate context for child
• Non-trivial to share data between processes – Need to use files/pipes to share data
– Can use shared memory
– Lots of overhead!
Process Cons

View of a Process
• Process = context + code, data, and stack
Process context
Code, data, and stack
stack
shared libraries
run-time heap
read/write data
read-only code/data
SP
Program context:
Data registers
Condition codes
Stack pointer (SP)
Program counter (PC) Kernel context:
VM structures Descriptor table
PC
0

View of a Process
• Process = context + code, data, and stack
Process context
Code, data, and stack
stack
shared libraries
run-time heap
read/write data
read-only code/data
SP
Program context:
Data registers
Condition codes
Stack pointer (SP)
Program counter (PC)
Kernel context: VM structures
Descriptor table
PC
0

Alternate View of a Process
• Process = thread + code, data, and kernel context
SP
Thread (main thread)
stack
Code and Data
shared libraries
run-time heap
read/write data
read-only code/data
Thread context:
Data registers Condition codes Stack pointer (SP) Program counter (PC)
PC
0
Kernel context: VM structures
Descriptor table

A Process With Multiple Threads
• Multiple threads can be associated with a process – Eachthreadhasitsownlogicalcontrolflow
Thread 1 (main thread)
stack 1
Shared code and data Thread 2 (peer thread)
stack 2
shared libraries
run-time heap
read/write data
read-only code/data
Thread 1 context: Data registers Condition codes SP1
PC1
0
Thread 2 context: Data registers Condition codes SP2
PC2
Kernel context: VM structures
Descriptor table

A Process With Multiple Threads
• Multiple threads can be associated with a process
– Eachthreadhasitsownlogicalcontrolflow
– Eachthreadsharesthesamecode,data,andkernelcontext
Thread 1 (main thread)
stack 1
Shared code and data Thread 2 (peer thread)
stack 2
shared libraries
run-time heap
read/write data
read-only code/data
Thread 1 context: Data registers Condition codes SP1
PC1
0
Thread 2 context: Data registers Condition codes SP2
PC2
Kernel context: VM structures
Descriptor table

A Process With Multiple Threads
• Multiple threads can be associated with a process
– Eachthreadhasitsownlogicalcontrolflow
– Eachthreadsharesthesamecode,data,andkernelcontext – Eachthreadhasitsownstackforlocalvariables
Thread 1 (main thread)
stack 1
Shared code and data Thread 2 (peer thread)
stack 2
shared libraries
run-time heap
read/write data
read-only code/data
Thread 1 context: Data registers Condition codes SP1
PC1
0
Thread 2 context: Data registers Condition codes SP2
PC2
Kernel context: VM structures
Descriptor table

A Process With Multiple Threads
• Multiple threads can be associated with a process
– Eachthreadhasitsownlogicalcontrolflow
– Eachthreadsharesthesamecode,data,andkernelcontext
– Eachthreadhasitsownstackforlocalvariables • but not protected from other threads
Thread 1 (main thread)
stack 1
Shared code and data
Thread 2 (peer thread)
stack 2
shared libraries
run-time heap
read/write data
read-only code/data
Thread 1 context: Data registers Condition codes SP1
PC1
0
Thread 2 context: Data registers Condition codes SP2
PC2
Kernel context: VM structures
Descriptor table

A Process With Multiple Threads
• Multiple threads can be associated with a process
– Eachthreadhasitsownlogicalcontrolflow
– Eachthreadsharesthesamecode,data,andkernelcontext
– Eachthreadhasitsownstackforlocalvariables • but not protected from other threads
– Eachthreadhasitsownthreadid(TID)
Thread 1 (main thread)
stack 1
Shared code and data
Thread 2 (peer thread)
stack 2
shared libraries
run-time heap
read/write data
read-only code/data
Thread 1 context: Data registers Condition codes SP1
PC1
0
Thread 2 context: Data registers Condition codes SP2
PC2
Kernel context: VM structures
Descriptor table

OS: Concept of a Thread
Process
(typically functions)
Threads
• Processes
– Represent an entire program
• Threads
– Represents smaller chunks of code

OS: Concept of a Thread
Process
(typically functions)
Threads
• Processes
– Represent an entire program – High Overhead context switch
• Threads
– Represents smaller chunks of code – Lower Overhead context switch

Logical View of Threads
• Threads associated with process form a pool of peers – Unlike processes which form a tree hierarchy
Threads associated with process foo
Process hierarchy P0
P1
T2 T1
T4
shared code, data and kernel context
sh
foo
bar
sh sh
T5
T3

Threads vs. Processes
• Howthreadsandprocessesaresimilar – Each has its own logical control flow
– Each can run concurrently with others
– Each is context switched

Threads vs. Processes
• Howthreadsandprocessesaresimilar – Each has its own logical control flow
– Each can run concurrently with others
– Each is context switched
• Howthreadsandprocessesaredifferent – Threads share code and some data
• Processes (typically) do not

Threads vs. Processes
• Howthreadsandprocessesaresimilar – Each has its own logical control flow
– Each can run concurrently with others
– Each is context switched
• Howthreadsandprocessesaredifferent – Threads share code and some data
• Processes (typically) do not
– Threads are somewhat less expensive than processes
• Process control is twice as expensive as thread control • Linux numbers:
– ~20K cycles to create and reap a process
– ~10K cycles (or less) to create and reap a thread