63
Experiencing processes and threads Hung-Wei Tseng

6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Experiencing processes and threadsHung-Wei Tseng

Page 2: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Recap: Tasks/processes

!2

Virtual memoryheap

code

static data

code

stack

CPUMemory

I/O

Task #1

PC

a = 0x01234567

Virtual memoryheap

code

static data

code

stack

CPUMemory

I/O

Task #2

PC

a = 0xDEADBEEF

Virtual memoryheap

code

static data

code

stack

CPUMemory

I/O

Task #3

PC

a = 0x87654321

Virtual memoryheap

code

static data

code

stack

CPUMemory

I/O

Task #4

PC

a = 0x95273310

Each process has its own unique virtual memory address space, its own states of execution, its own set of I/Os

Page 3: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!3

The same processor!The same memory

address!

Different values

Different values are preserved

Page 4: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Recap: Threads

!4

Virtual memoryheap

code

static data

code

stack

Task #1

a = 0x01234567

CPUPCThread #1

CPUPCThread #2

CPU PCThread #3

Virtual memoryheap

code

static data

code

stack

Task #2

a = 0x01234567

CPUPCThread #1

CPUPCThread #2

CPU PCThread #3

Each process has its own unique virtual memory address space, its own states of execution, its own set of I/Os

Each thread has its own PC, states of execution, but shares memory address spaces, I/Os without threads within the

same process

Page 5: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Threads + shared memory in a process • Processes + IPC/files/sockets • Processes + special shared memory module/library (e.g.,

boost)

!5

Recap: Parallelizing an application

Page 6: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• pid_t fork(); • fork used to create processes (UNIX) • What does fork() do?

• Creates a new address space (for child) • Copies parent’s address space to child’s • Points kernel resources to the parent’s resources (e.g. open files) • Inserts child process into ready queue

• fork() returns twice • Returns the child’s PID to the parent • Returns “0” to the child

!6

Recap: process API — fork()

Page 7: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Process API • Thread programming and synchronization

!7

Outline

Page 8: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

The interface of managing processes (cont.)

!8

Page 9: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• What happens if we execute the following code?int main() {

int pid; if ((pid = fork()) == 0) { printf (”My pid is %d\n", getpid()); } printf (”Child pid is %d\n", pid); return 0;}

!9

Recap: What will happen?

# of times “my pid” is printed my pid values printed # of times “child pid” is printed child pid values printed

A 1 7 2 7, 0B 1 2 2 7, 0C 2 7, 2 1 7D 1 0 2 7, 2E 1 7 1 7

Assume the parent’s PID is 2; child’s PID is 7.

Page 10: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• void exit(int status) • exit frees resources and terminates the process

• Runs an functions registered with atexit • Flush and close all open files/streams • Releases allocated memory. • Remove process from kernel data structures (e.g. queues)

• status is passed to parent process • By convention, 0 indicates “normal exit”

!10

exit()

Page 11: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• What happens if we add an exit?int main() {

int pid; if ((pid = fork()) == 0) { printf (”My pid is %d\n", getpid()); exit(0); } printf (”Child pid is %d\n", pid); return 0;

}

!15

If we add an exit …Assume the parent’s PID is 2; child’s PID is 7.

# of times “my pid” is printed my pid values printed # of times “child pid” is printed child pid values printed

A 1 7 2 7, 0B 1 2 2 7, 0C 2 7, 2 1 7D 1 0 2 7, 2E 1 7 1 7

Page 12: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!16

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Page 13: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!17

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Page 14: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!18

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Output: My pid is 7

Page 15: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!19

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Output: My pid is 7

Page 16: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!20

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7

Output: My pid is 7

Page 17: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!21

Virtual memory

int pid;

if ((pid = fork()) == 0) { printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7

Output: My pid is 7Child pid is 7

Page 18: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• What happens if we add an exit?int main() {

int pid; if ((pid = fork()) == 0) { printf (”My pid is %d\n", getpid()); exit(0); } printf (”Child pid is %d\n", pid); return 0;

}

!22

If we add an exit …

# of times “my pid” is printed my pid values printed # of times “child pid” is printed child pid values printed

A 1 7 2 7, 0B 1 2 2 7, 0C 2 7, 2 1 7D 1 0 2 7, 2E 1 7 1 7

Assume the parent’s PID is 2; child’s PID is 7.

Page 19: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Consider the following codefork();printf(“moo\n”);fork();printf(“oink\n”);fork();printf(“baa\n”);How many animal noises will be printed?

A. 3 B. 6 C. 8 D. 14 E. 24

!27

More forks

2x4x8x

Page 20: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• int execvp(char *prog, char *argv[]) • fork does not start a new program, just duplicates the current

program • What execvp does:

• Stops the current process • Overwrites process’ address space for the new program • Initializes hardware context and args for the new program • Inserts the process into the ready queue

• execvp does not create a new process

!28

Starting a new program with execvp()

Page 21: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Windows only has exec • Flexibility • Allows redirection & pipe

• The shell forks a new process whenever user invoke a program • After fork, the shell can setup any appropriate environment

variable to before exec • The shell can easily redirect the output in shell: a.out > file

!29

Why separate fork() and exec()

Page 22: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

exec()

!30

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Page 23: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!31

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Page 24: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!32

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Output: Child pid is 7

Page 25: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!33

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

7 0

Output: Child pid is 7

Page 26: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

fork() and exit()

!34

Virtual memory

int pid; if ((pid = fork()) == 0) { execvp(“a.out”,NULL); printf(“My pid is %d\n”, getpid()); exit(); } printf(“Child pid is %d\n”, pid);

static data

pid: ? stack

heap

code

Virtual memory

int main() { printf(“I am someone else now!\n”); }

static data

pid: ? stack

heap

code

7 0

Output: Child pid is 7I am someone else now!

Page 27: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Let’s write our own shells

!35

Page 28: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Say, we want to do ./a • fork • exec(“./a”, NULL)

!36

How to implement a shell

Page 29: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Say, we want to do ./a • fork • exec(“./a”, NULL)

!37

How to implement redirection in shell

Virtual memory

int pid, fd; char cmd[2048], prompt = “myshell$” while(gets(cmd) != NULL) { if ((pid = fork()) == 0) { execv(cmd,NULL); } else printf(“%s ”,prompt); }

static data

stack

heap

code

Virtual memory

int pid, fd; char cmd[2048], prompt = “myshell$” while(gets(cmd) != NULL) { if ((pid = fork()) == 0) { execv(cmd,NULL); } else printf(“%s ”,prompt); }

static data

stack

heap

code

The shell can respond to next input

Page 30: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Say, we want to do ./a > b.txt • fork • The forked code opens b.txt • The forked code dup the file descriptor • The forked code assigns b.txt to stdin/stdout • The forked code closes b.txt • exec(“./a”, NULL)

!38

How to implement redirection in shell

Page 31: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Say, we want to do ./a > b.txt • fork • The forked code opens b.txt • The forked code dup the file descriptor to stdin/stdout • The forked code closes b.txt • exec(“./a”, NULL)

!39

How to implement redirection in shell

Virtual memory

int pid, fd; char cmd[2048], prompt = “myshell$” while(gets(cmd) != NULL) { if ((pid = fork()) == 0) { fd = open(“b.txt”, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); dup2(fd, stdout); close(fd); execv(“./a”,NULL); } else printf(“%s ”,prompt); }

static data

stack

heap

code

Virtual memory

int pid, fd; char cmd[2048], prompt = “myshell$” while(gets(cmd) != NULL) { if ((pid = fork()) == 0) { fd = open(“b.txt”, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); dup2(fd, stdout); close(fd); execv(“./a”,NULL); } else printf(“%s ”,prompt); }

static data

stack

heap

code

The shell can respond to next input

Homework for you:Think about the case when your fork is equivalent to fork+exec()

Page 32: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• pid_t wait(int *stat) • pid_t waitpid(pid_t pid, int *stat, int opts)

• wait / waitpid suspends process until a child process ends • wait resumes when any child ends • waitpid resumes with child with pid ends • exit status info 1 is stored in *stat • Returns pid of child that ended, or -1 on error

• Unix requires a corresponding wait for every fork

!40

wait()

Page 33: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Zombie: process that exits but whose parent doesn’t call wait • Can’t be killed normally • Resources freed but pid remains in use

• Orphan: Process whose parent has exited before it has • Orphans are adopted by init process, which calls wait periodically

!41

Zombies, Orphans, and Adoption

Page 34: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Thread programming & synchronization

!42

Page 35: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

The virtual memory of multithreaded applications

!43

Virtual memory

heap

code

static data

stack #1

stack #2

stack #3

Everything here is shared/visible among all threads within the same process!

Page 36: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Joint Banking

!44

withdraw$20

deposit$10

current balance: $40

Bank of UCR

What is the new balance each would see?

Page 37: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Bank Account Race Condition

!49

Step 1: TA runs and calls getBalance followed by adding amt (10) to bal

current balance: $40current balance: $50deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 38: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Bank Account Race Condition

!50

Step 2: Switch to TB which calls getBalance, followed by subtracting amt (20) from bal

current balance: $20current balance: $50deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 39: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Bank Account Race Condition

!51

Step 3: Switch back to TA which calls setBalance

current balance: $20current balance: $50deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 40: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Bank Account Race Condition

!52

Step 4: Switch back to and finish TB by calling setBalance, followed by printReceipt

current balance: $20current balance: $50deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 41: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Bank Account Race Condition

!53

Step 5: Finish TA by calling checkBalance, followed by printReceipt

current balance: $20current balance: $20deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Honey, we need to chat

Page 42: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• If the shared variable, balance, initially has the value of 40, what value(s) might it hold after threads A and B finish after we call deposit(10) and withdraw(20)?

A. 30 B. 20 or 30 C. 20, 30, or 50 D. 10, 20, or 30

!54

Joint Banking

deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 43: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Processor/compiler may reorder your memory operations/instructions

• Each processor core may not run at the same speed (cache misses, branch mis-prediction, I/O, voltage scaling and etc..)

• Threads may not be executed/scheduled right after it’s spawned

!55

Processors/threads are not-deterministic

Page 44: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Concurrency leads to multiple active processes/threads that share one or more resources

• Synchronization involves the orderly sharing of resources • All threads must be on the same page • Need to avoid race conditions

!56

Synchronization

Page 45: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Protect some pieces of code that access shared resources (memory, device, etc.)

• For safety, critical sections should: • Enforce mutual exclusion (i.e. only one thread at a time) • Execute atomically (all-or-nothing) before allowing another thread

!57

Critical sections

Page 46: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Which is the smallest code region in Thread A that we can make as a critical section to guarantee the outcome as 30?

!62

Identifying Critical Sections

int deposit(int amt) { int bal; bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); return bal; }

Thread Aint withdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance();

printReceipt(bal); return bal; }

Thread B

AB

C D E

Page 47: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Critical sections

!63

deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread Awithdraw(int amt) { int bal;

bal = getBalance(); bal = bal - amt; setBalance(bal); bal = checkBalance(); printReceipt(bal); }

Thread B

Page 48: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Entry section acts as barrier, only allowing a single thread in at a time

• Exit section should remove barrier for other threads’ entry

!64

Critical section

deposit(int amt) { int bal;

bal = getBalance(); bal = bal + amt; setBalance(bal); bal = checkBalance();

printReceipt(bal); }

entry section

exit section

Page 49: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

1. Mutual exclusion — at most one process/thread in its critical section

2. Progress/Fairness — a thread outside of its critical section cannot block another thread from entering its critical section

3. Progress/Fairness — a thread cannot be postponed indefinitely from entering its critical section

4. Accommodate nondeterminism — the solution should work regardless the speed of executing threads and the number of processors

!65

Solving the “Critical Section Problem”

Page 50: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

How to implement lock/unlock

!66

Page 51: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

The baseline

!67

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n”, \ balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

void * mythread(void *arg) { char *letter = arg; int i; // stack (private per thread) printf("%s: begin [addr of i: %p]\n", letter, &i); for (i = 0; i < max; i++) { balance = balance + 1; // shared: only one } printf("%s: done\n", letter); return NULL; }

int max; volatile int balance = 0; // shared global variable

Page 52: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!68

int max; volatile int balance = 0; // shared global variablepthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; for (i = 0; i < max; i++) { Pthread_mutex_lock(&lock); balance++; Pthread_mutex_unlock(&lock); } printf("%s: done\n", letter); return NULL; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

Use pthread_lock

Page 53: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!69

int max; volatile int balance = 0; // shared global variablepthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; Pthread_mutex_lock(&lock); for (i = 0; i < max; i++) {

balance++; } Pthread_mutex_unlock(&lock); printf("%s: done\n", letter); return NULL; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

Use pthread_lock (coarser grain)

Page 54: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!70

int max; volatile int balance = 0; // shared global variablevolatile unsigned int lock = 0;

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; for (i = 0; i < max; i++) { SpinLock(&lock); balance++; SpinUnlock(&lock); } printf("%s: done\n", letter); return NULL; }

Use spin locks

void SpinLock(volatile unsigned int *lock) { while (*lock == 1) // TEST (lock) ; // spin *lock = 1; // SET (lock) }

void SpinUnlock(volatile unsigned int *lock) { *lock = 0; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

what if context switch happens here?

Page 55: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Which of the following can disabling interrupts guarantee on multicore processors?

A. At most one process/thread in its critical section B. A thread outside of its critical section cannot block another

thread from entering its critical section C. A thread cannot be postponed indefinitely from entering its

critical section D. The solution should work regardless the speed of executing

threads and the number of processors E. None of the above

!75

Disable interrupts?

What if the thread hold the critical section crashes?

What if we have multiple processors?

What if we have multiple processors?

Page 56: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!76

int max; volatile int balance = 0; // shared global variablevolatile unsigned int lock = 0;

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; for (i = 0; i < max; i++) { SpinLock(&lock); balance++; SpinUnlock(&lock); } printf("%s: done\n", letter); return NULL; }

Use spin locks

void SpinLock(volatile unsigned int *lock) { while (*lock == 1) // TEST (lock) ; // spin *lock = 1; // SET (lock) }

void SpinUnlock(volatile unsigned int *lock) { *lock = 0; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

what if context switch happens here?

— the lock must be updated atomically

Page 57: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; for (i = 0; i < max; i++) { SpinLock(&lock); balance++; SpinUnlock(&lock); } printf("%s: done\n", letter); return NULL; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

!77

int max; volatile int balance = 0; // shared global variablevolatile unsigned int lock = 0;

Use spin locks

static inline uint xchg(volatile unsigned int *addr, unsigned int newval) { uint result; asm volatile("lock; xchgl %0, %1" : "+m" (*addr), "=a" (result) : "1" (newval) : "cc"); return result; }

void SpinLock(volatile unsigned int *lock) { // what code should go here? }

void SpinUnlock(volatile unsigned int *lock) { // what code should go here? }

a prefix to xchgl that locks the whole cache lineexchange the content in %0 and %1

Page 58: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

void * mythread(void *arg) { char *letter = arg; printf("%s: begin\n", letter); int i; for (i = 0; i < max; i++) { SpinLock(&lock); balance++; SpinUnlock(&lock); } printf("%s: done\n", letter); return NULL; }

int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: main-first <loopcount>\n"); exit(1); } max = atoi(argv[1]); pthread_t p1, p2; printf("main: begin [balance = %d] [%x]\n", balance, (unsigned int) &balance); Pthread_create(&p1, NULL, mythread, "A"); Pthread_create(&p2, NULL, mythread, "B"); // join waits for the threads to finish Pthread_join(p1, NULL); Pthread_join(p2, NULL); printf("main: done\n [balance: %d]\n [should: %d]\n", balance, max*2); return 0; }

!78

int max; volatile int balance = 0; // shared global variablevolatile unsigned int lock = 0;

Use spin locks

static inline uint xchg(volatile unsigned int *addr, unsigned int newval) { uint result; asm volatile("lock; xchgl %0, %1" : "+m" (*addr), "=a" (result) : "1" (newval) : "cc"); return result; }

void SpinLock(volatile unsigned int *lock) { while (xchg(lock, 1) == 1); }

void SpinUnlock(volatile unsigned int *lock) { xchg(lock, 0); }

Page 59: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Semaphores

!79

Page 60: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Also referred to as “producer-consumer” problem • Producer places items in shared buffer • Consumer removes items from shared buffer

!80

Bounded-Buffer Problem

producer consumer

5 22 18 38 2 15buffer

Page 61: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

Without synchronization, you may write

!81

int main(int argc, char *argv[]) { pthread_t p; printf("parent: begin\n"); // init here Pthread_create(&p, NULL, child, NULL); int in = 0; while(TRUE) { int item = …; buffer[in] = item; in = (in + 1) % BUFF_SIZE; } printf("parent: end\n"); return 0; }

void *child(void *arg) { int out = 0; printf("child\n"); while(TRUE) { int item = buffer[out]; out = (out + 1) % BUFF_SIZE; // do something w/ item } return NULL; }

int buffer[BUFF_SIZE]; // shared global

Page 62: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

!82

Use locksint main(int argc, char *argv[]) { pthread_t p; printf("parent: begin\n"); // init here Pthread_create(&p, NULL, child, NULL); int in = 0; while(TRUE) { int item = …; Pthread_mutex_lock(&lock); buffer[in] = item; in = (in + 1) % BUFF_SIZE; Pthread_mutex_unlock(&lock); } printf("parent: end\n"); return 0; }

void *child(void *arg) { int out = 0; printf("child\n"); while(TRUE) { Pthread_mutex_lock(&lock); int item = buffer[out]; out = (out + 1) % BUFF_SIZE; Pthread_mutex_unlock(&lock); // do something w/ item } return NULL; }

int buffer[BUFF_SIZE]; // shared globalvolatile unsigned int lock = 0;

You cannot produce and consume simultaneously!

Page 63: 6 Processes and threads - University of California, Riversidehtseng/classes/cs202... · Task #1 a = 0x01234567 CPU PC Thread #1 PC CPU Thread #2 CPU PC Thread #3 Virtual memoryheap

• Reading quiz due next Tuesday • Project will be up next Tuesday after class

• You need to install Ubuntu 16.04.6 in VirtualBox • You can have up to 1 classmate working together with you — 2 in a

group

!94

Announcement