CS计算机代考程序代写 UNIS Template

UNIS Template

Processes and Threads

Shuaiwen Leon Song

USYD Future System Architecture Lab (FSA)

https://shuaiwen-leon-song.github.io/

https://shuaiwen-leon-song.github.io/

• To understand what a process is

• To learn the basics of exceptional control flow

• To learn how to control child processes

• To learn about other process related
functions

• To learn how to load and execute programs

• To learn about signals

• To learn about pipes

Objectives

How to run programs?

› How does the operating system run programs?

3

How to run programs?

› How does the operating system run programs?

› Need abstraction of executing program

4

How to run programs?

› How does the operating system run programs?

› Need abstraction of executing program

› process = memory state + machine state

5

The OS must handle multiple processes
in execution at any given time…

How do we do this?

Multi-Processing

What is a process?

› 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

7

How do we control process?

›We need to identify process:
› Get process id use getpid() function

8

#include

#include

int main(int argc, char const *argv[])

{

printf(“pid = %d\n”, getpid());

return 0;

}

https://linux.die.net/man/3/getpid

How do we control process?

›Need a way to create and destroy processes

9

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)

Create & Terminate Processes

More detailed POSIX signals refer to : https://en.wikipedia.org/wiki/Signal_(IPC)

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

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”);

}

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”);

}

Parent

Child

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”);

}

Parent

Child

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”);

}

pid_t pid = fork();

if (pid == 0) {

printf(“hello from child\n”);

} else {

printf(“hello from parent\n”);

}

Create & Terminate Processes

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

http://linux.die.net/man/2/fork
http://en.wikipedia.org/wiki/Copy-on-write
http://en.wikipedia.org/wiki/Data_segment#Program_memory

What does this print out?

void main()

{

printf(“L0\n”);

fork();

printf(“L1\n”);

fork();

printf(“Bye\n”);

}

L1 Bye

Bye

L0 L1 Bye

Bye

Create & Terminate Processes

What does this print out?

void main()

{

printf(“L0\n”);

fork();

printf(“L1\n”);

fork();

printf(“L2\n”);

fork();

printf(“Bye\n”);

}

Bye

L2 Bye

Bye

L1 L2 Bye

Bye

L2 Bye

Bye

L0 L1 L2 Bye

Does it always print inorder?

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”);

}

How many linesof output will it produce?

A) 4

B) 5

C) 6

D) 7

E) 8

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
donglin@ubuntu:~/ctest$ ./main

Running Parent, PID = 24753

Terminating Child, PID = 24754

donglin@ubuntu:~/ctest$ kill -9 24754

donglin@ubuntu:~/ctest$ ps

PID TTY TIME CMD

24721 pts/4 00:00:00 bash

24753 pts/4 00:00:04 main

24754 pts/4 00:00:00 main

24755 pts/4 00:00:00 ps

Create & Terminate Processes

Linux
Zombie process cannot be killed, kill the
parent process instead.

Create & Terminate Processes

What about this one?

Zombie?

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);

}

}

Create & Terminate Processes

donglin@ubuntu:~/ctest$ ./main

Terminating Parent, PID = 24950

Running Child, PID = 24951

donglin@ubuntu :~/ctest$ ps -f

UID PID PPID C STIME TTY TIME CMD

donglin 24911 24910 0 13:39 pts/5 00:00:00 -bash

donglin 24951 1 99 13:40 pts/5 00:00:27 ./main

donglin 24957 24911 0 13:40 pts/5 00:00:00 ps -f

Create & Terminate Processes

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?

So, how do we “reap” a child process
programmatically?

wait()

waitpid()

Zombie?

Create & Terminate Processes

kill -s SIGCHLD pid

int wait(int *child_status)

void main()

{

pid_t pid[N];

int i;

int child_status;

for (i = 0; i < N; i++) { 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", wpid, WEXITSTATUS(child_status)); } else { printf("Child %d terminated abnormally\n", wpid); } } } fork a childprocesses 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++) { 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", wpid, WEXITSTATUS(child_status)); } else { printf("Child %d terminated abnormally\n", wpid); } } } wait for each toterminate 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++) { 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", wpid, WEXITSTATUS(child_status)); } else { printf("Child %d terminated abnormally\n", wpid); } } } wait for each toterminate Get Info on Status Create & Terminate Processes int waitpid(pid, &status, options void main() { pid_t pid[N]; int i; int child_status; for (i = 0; i < N; i++) { if ((pid[i] = fork()) == 0) { // Child exit(100+i); } } for (i = N-1; 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”,

wpid, WEXITSTATUS(child_status));

} else {

printf(“Child %d terminated abnormally\n”, wpid);

} } }

wait for specific child to terminate

Create & Terminate Processes

int waitpid(-1, &status, 0)

is the same as…

int wait(&status)

Create & Terminate Processes

void main()

{

if (fork() == 0) {

printf(“a”);

}

else {

printf(“b”);

waitpid(-1, NULL, 0);

}

printf(“c”);

exit(0);

}

What is the output of the programon
the left?

A. acbc
B. bcac
C. abcc
D. bacc
E. A or C orD

Activity

void main()

{

if (fork() == 0) {

printf(“a”);

}

else {

printf(“b”);

waitpid(-1, NULL, 0);

}

printf(“c”);

exit(0);

}

What is the output of the programon
the left?

A. acbc
B. bcac
C. abcc
D. bacc
E. A orC or D

Activity

Putting a process to sleep: zzzzz…

› unsigned int sleep(unsigned int seconds);

41

#include

void main()

{

int amt = sleep(5);

}

Returns the number of seconds left to
sleep if a signal woke up the
process.

Returns 0 if time has elapsed.

Putting a process to sleep: zzzzz…

› int pause(void);

42

#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

Loading and Running Programs

43

What does a shell program do?

A shell program is a special kind of program whose
primary responsibility is to run otherprograms.

ls

ps

emacs

vim

cd

int execve(const char* filename,

const

const

char*

char*

argv[],

envp[]);

Loading and Running Programs

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)

https://en.wikipedia.org/wiki/Computing
https://en.wikipedia.org/wiki/Operating_system
https://en.wikipedia.org/wiki/Executable_file
https://en.wikipedia.org/wiki/Process_(computing)
https://en.wikipedia.org/wiki/Unix-like
https://en.wikipedia.org/wiki/Process_identifier
https://en.wikipedia.org/wiki/Machine_code
https://en.wikipedia.org/wiki/Data_(computing)
https://en.wikipedia.org/wiki/Heap_(programming)
https://en.wikipedia.org/wiki/Run-time_stack

We know what these are…

Loading and Running Programs

int execve(const char* filename,

const

const

char*

char*

argv[],

envp[]);

We know what these are…

But, what is this?

Loading and Running Programs

int execve(const char* filename,

const

const

char*

char*

argv[],

envp[]);

Every program runs in an “environment”. The environment
is customized using environment variables: PATH, EDITOR, …

envp[0]

envp[1]

envp[n-‐1]

NULL

envp “USER=richards”

“SHELL=/bin/bash”

“EDITOR=emacs”

Loading and Running Programs

int execve(const char* filename,

const

const

char*

char*

argv[],

envp[]);

It turns out that the more general form for main is:

int main(int argc,

const char* argv[],

const char* envp[]);

Loading and Running Programs

int execve(const char* filename,

const

const

char*

char*

argv[],

envp[]);

Loading and Running Programs

49

› Where are argv and envp in memory when a process executes?

50

Loading and Running Programs

Where are argvand envp
In memory when a process
executes?

Null-‐terminated environment variable strings

Null-‐terminated command-‐line argument 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

Bottomof stack

Top of stack

51

Loading and Running Programs

Where are argvand envp
In memory when a process
executes?

So, how do we accessthe
environment variables?

Null-‐terminated environment variable strings

Null-‐terminated command-‐line argument 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

Bottomof stack

Top of stack

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.

Loading and Running Programs

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
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 tries to divide by 0:
OS sends it a SIGFPE signal

If a process executesan
illegal instruction:
OS sends it a SIGILL signal

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
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 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 SIGCHLDsignal

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.

Signals

› 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

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.

Signals

So, how are they implemented?

Process 1

0 0 0 0 … 0

Pending

0 0 0 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

0 0 0 0 … 0

Blocked

Kernel

Signals

So, how are they implemented?

Process 1

0 0 0 0 … 0

Pending

0 0 0 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

0 0 0 0 … 0

Blocked

Kernel

Each process structurecontainsa pending and blocked bit vector.
Each entry corresponds to a specific signal.

Signals

So, how are they implemented?

Process 1

0 0 0 0 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

A process can decideto block a signal by setting
the correspondingbit in the blockedbit vector.

Signals

So, how are they implemented?

Process 1

0 0 0 0 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

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

Signals

So, how are they implemented?

Process 1

0 0 0 0 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

Imagine the processorencounters an illegal instruction
during the execution of Process 1

SIGILL

Signals

So, how are they implemented?

Process 1

0 0 0 1 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

The kernel will set the correspondingbit in the Pending bit vector

SIGILL
SIGILL

Signals

So, how are they implemented?

Process 1

0 0 0 1 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

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

SIGILL

?

Signals

So, how are they implemented?

Process 1

0 0 0 1 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

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

SIGILL

?

Signals

So, how are they implemented?

Process 1

0 0 0 1 … 0

Pending

0 0 1 0 … 0

Blocked

Process 2

0 0 0 0 … 0

Pending

1 0 0 0 … 0

Blocked

Kernel

The default behavior for SIGILL is to terminate the process

SIGILL

Signals

0 0 0 0 … 0

0 0 1 0 … 0

Blocked

0 0 0 0 … 0

1 0 0 0 … 0

Blocked

Process 1 Process 2
Kernel

Pending Pending

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

So, how are they implemented?
#include

int kill(pid_t pid, int sig);

Signals

0 0 0 0 … 1

0 0 1 0 … 0

Blocked

0 0 0 0 … 0

1 0 0 0 … 0

Blocked

Process 1 Process 2
Kernel

Pending Pending

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

So, how are they implemented?
#include

int kill(pid_t pid, int sig);

SIGINT

Signals

0 0 0 0 … 1

0 0 1 0 … 0

Blocked

0 0 0 0 … 0

1 0 0 0 … 0

Blocked

Process 1 Process 2
Kernel

Pending Pending

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

So, how are they implemented?
#include

int kill(pid_t pid, int sig);

SIGINT

Signals

0 0 0 0 … 1

0 0 1 0 … 0

Blocked

0 0 0 0 … 0

1 0 0 0 … 0

Blocked

Process 1 Process 2
Kernel

Pending Pending

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

So, how are they implemented?
#include

int kill(pid_t pid, int sig);

SIGINT

Signals

We can send signals from the keyboard

ctrl-c
Typing ctrl-c from 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 processgroup.

ctrl-z
Typing ctrl-‐zfrom 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 processgroup.

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
calling process aftersecs seconds.

Need a handler to “catch” the signal
and do something interesting.

Signals

Register signal handler

#include

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t

handler);

The signal

Sets the disposition of the signal
signum to handler

Signals

Signals

77

#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.

• 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

Process Pros

• Forking a process is expensive

– Need to clone parent’s memory space

– Need to setup a separate context for child

Process Cons

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.

• 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

• Process = context + code, data, and stack

shared libraries

0

Program context:

Data registers
Condition codes
Stack pointer (SP)
Program counter (PC)

Kernel context:

VM structures
Descriptor table

Code, data, and stack

run-time heap

read/write data

read-only code/data

stack
SP

PC

Process context

View of a Process

• Process = context + code, data, and stack

shared libraries

0

Program context:

Data registers
Condition codes
Stack pointer (SP)
Program counter (PC)

Kernel context:

VM structures
Descriptor table

Code, data, and stack

run-time heap

read/write data

read-only code/data

stack
SP

PC

Process context

View of a Process

0

Thread context:

Data registers

Condition codes

Stack pointer (SP)
Program counter (PC)

run-time heap

read/write data

read-only code/data

stack
SP

PC

• Process = thread + code, data, and kernel context

Thread (main thread) Code and Data

shared libraries

Kernel context:

VM structures
Descriptor table

Alternate View of a Process

• Multiple threads can be associated with a process
– Each thread has its own logical control flow

shared libraries

0

Thread 1 context:

Data registers
Condition codes
SP1
PC1

Shared code and data

run-time heap

read/write data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context:

VM structures
Descriptor table

Thread 2 context:

Data registers
Condition codes
SP2
PC2

stack 2

Thread 2 (peer thread)

A Process With Multiple Threads

• Multiple threads can be associated with a process
– Each thread has its own logical control flow

– Each thread shares the same code, data, and kernel context

shared libraries

0

Thread 1 context:

Data registers
Condition codes
SP1
PC1

Shared code and data

run-time heap

read/write data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context:

VM structures
Descriptor table

Thread 2 context:

Data registers
Condition codes
SP2
PC2

stack 2

Thread 2 (peer thread)

A Process With Multiple Threads

• Multiple threads can be associated with a process
– Each thread has its own logical control flow

– Each thread shares the same code, data, and kernel context

– Each thread has its own stack for local variables

shared libraries

0

Thread 1 context:

Data registers
Condition codes
SP1
PC1

Shared code and data

run-time heap

read/write data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context:

VM structures
Descriptor table

Thread 2 context:

Data registers
Condition codes
SP2
PC2

stack 2

Thread 2 (peer thread)

A Process With Multiple Threads

• Multiple threads can be associated with a process
– Each thread has its own logical control flow

– Each thread shares the same code, data, and kernel context

– Each thread has its own stack for local variables
• but not protected from other threads

shared libraries

0

Thread 1 context:

Data registers
Condition codes
SP1
PC1

Shared code and data

run-time heap

read/write data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context:

VM structures
Descriptor table

Thread 2 context:

Data registers
Condition codes
SP2
PC2

stack 2

Thread 2 (peer thread)

A Process With Multiple Threads

• Multiple threads can be associated with a process
– Each thread has its own logical control flow

– Each thread shares the same code, data, and kernel context

– Each thread has its own stack for local variables
• but not protected from other threads

– Each thread has its own thread id (TID)

0

Thread 1 context:

Data registers
Condition codes
SP1
PC1

run-time heap

read/write data

read-only code/data

stack 1

Thread 1 (main thread)

Kernel context:

VM structures
Descriptor table

Thread 2 context:

Data registers
Condition codes
SP2
PC2

stack 2

Shared code and data Thread 2 (peer thread)

shared libraries

A Process With Multiple Threads

(typically functions)

Process

• Processes
– Represent an entire program

• Threads
– Represents smaller chunks of code

Threads

OS: Concept of a Thread

(typically functions)

Process

• Processes
– Represent an entire program

– High Overhead context switch

• Threads
– Represents smaller chunks of code

– Lower Overhead context switch

Threads

OS: Concept of a Thread

• Threads associated with process form a pool of peers

– Unlike processes which form a tree hierarchy

P0

P1

sh sh sh

foo

bar

T1

Process hierarchyThreads associated with process foo

T2
T4

T5 T3

shared code, data
and kernel context

Logical View of Threads

• How threads and processes are similar

– Each has its own logical control flow

– Each can run concurrently with others

– Each is context switched

Threads vs. Processes

• How threads and processes are similar

– Each has its own logical control flow

– Each can run concurrently with others

– Each is context switched

• How threads and processes are different

– Threads share code and some data

• Processes (typically) do not

Threads vs. Processes

• How threads and processes are similar

– Each has its own logical control flow

– Each can run concurrently with others

– Each is context switched

• How threads and processes are different

– 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

Threads vs. Processes