Nachos Project 3 Lecturer: Hao-Hua Chu TA: Chun-Po Wang (Artoo) Date: 2008/10/25.
-
Upload
gerard-warren -
Category
Documents
-
view
223 -
download
2
Transcript of Nachos Project 3 Lecturer: Hao-Hua Chu TA: Chun-Po Wang (Artoo) Date: 2008/10/25.
Nachos Project 3
Lecturer: Hao-Hua Chu
TA: Chun-Po Wang (Artoo)
Date: 2008/10/25
2
Project 3
• Practice thread synchronization– Producer-consumer problem– Dining philosophers problem– Implement these problems with
Nachos thread and synchronization routines
3
Summary
• Motivation & Objective• Synchronization Problems• Nachos Synchronization Routines
– Semaphore– Lock– Condition
• Requirement• Submission
4
Motivation & Objective
• In previous project, you learnt to run multiple threads.– Now we should practice to make them
work together by implementing some classic synchronization problems
• Nachos has already implemented some class and routines to help you solve these problems
5
Synchronization Problems
• Producer-consumer problem– A fixed-size buffer– Producer generates data and put it into buffer– Consumer retrieves data from buffer– They work simultaneously– The objective is to make sure that
• producer won’t put data into buffer when it’s full• consumer won’t remove data from en empty buffer• the state of buffer is consistent after each action
BufferProducer Consumer
6
Producer-consumer problem
• When it comes to Nachos …– A buffer may be a global variable, e.g. a
global array– The consumer and the producer would be
threads• Where the problem lies …
– Threads may be yielded at any point– When both threads access the same data,
we must make sure that a thread won’t access it when another is working on it.
– Or, the data may be corrupted
7
Synchronization Problems (cont.)
• Dining philosophers problem– 5 philosophers, with 5
chopsticks– A philosopher can either think or
eat– When she/he want to eat,
she/he must take both chopsticks on her/his left and right
– If all philosophers hold one chopstick, we have a deadlock(philosophers are strange, aren’t they?)
http://en.wikipedia.org/wiki/Image:Dining_philosophers.png
8
Dining philosophers problem
• Now we deal with 5 threads, apparently
• Figure out a method to prevent deadlock– An easy solution is to make sure
that a philosopher need to pick up both chopsticks at the same time
9
Nachos synchronization classes
• code/thread/synch.h and synch.cc• Semaphore
– A counter for a set of available resources– Nachos promised that the actions on semaphores will
not be interrupted• Lock
– A lock can be either BUSY or FREE– Only the thread that acquired the lock can release it– Lock is implemented by semaphores
• Condition– A condition variable is used on monitors, where many
threads wait on this condition– We discuss condition variables when introducing
monitors later
10
Semaphore class
• int value; // value >= 0• P(): waits until value > 0, then decreases it• V(): increases the value, and wakes up a
thread waiting in P()• How does OS make these operations
atomic?– Disable interrupts (this method only works on
uniprocessor machines), or– Use special instructions (eg. test-and-set)– Nachos uses the former
11
Lock class
• A Lock is implemented by a Semaphore: – value 0 means busy, value 1 means free
• Acquire(): wait until the lock is free, then set it to busy (by calling Semaphore::P())
• Release(): release the lock and wake up a thread waiting on this lock (by calling Semaphore::V())– However, only the thread which acquired the lock
can release it– This is different to a semaphore
12
An example
• See class SynchConsoleOutput (code/userprog/synchconsole.cc)
void SynchConsoleOutput::PutChar(char ch){ lock->Acquire(); consoleOutput->PutChar(ch); waitFor->P(); lock->Release();}
void SynchConsoleOutput::CallBack(){ waitFor->V();}
13
Monitor
• “A monitor is an approach to synchronize two or more computer tasks that use a shared resource”
• Why use it? Why not just use semaphores?– Programmers are prone to errors
• A monitor consists of– Procedures for manipulating shared resources– A mutual exclusion lock: only one thread can
operate in a monitor at any time– Conditions (optional): sometimes a thread
operating in a monitor must wait for some condition to be true before it proceeds
14
Monitor example
• Following pseudo code demonstrate a channel which can only store one integer value at a time
monitor channel { int contents boolean full := false condition snd condition rcv
function send(int message) { while full do wait(rcv) contents := message full := true notify(snd) }
function receive() { var int received
while not full do wait(snd) received := contents full := false notify(rcv) return received }}//End of monitor
Source: http://en.wikipedia.org/wiki/Monitor_(synchronization)
15
Condition class
• Nachos DOES NOT provide a Monitor class, but it does provide a Condition class, which can be used to build a “monitor-style” C++ class– E.g. class SynchList
(code/thread/synchlist.cc), this is a List which can be accessed by multiple threads without any synchronization problems
16
Condition class (cont.)
• Wait(lock): a thread in a monitor waits for this condition. – The lock is supplied by the monitor which uses this
condition, because when a thread waits, it should release the lock for other threads to operate in the monitor
• Signal(): the condition is met, and a monitor wakes up a thread waiting on this condition.
• Broadcast(): just like Signal(), but now the monitor wakes up all threads waiting on the condition
17
Implementation
• Implements producer-consumer problem with semaphores and locks (built by Nachos)
• Implements dining philosopher problem with a monitor-style class (built by you)
18
Implementation (cont.)
• Make Nachos run producer-consumer problem with flag -PC, and run dining philosopher problem with flag -DP– Just like -K (ThreadSelfTest) and -S
(previous project) flags
19
Producer-Consumer problem
• Produce and consume 30 items: 0~29• The buffer size is 5• Print the item number you produced or consumed, and
the current total number of items in the shared buffer// Thread body for producervoid Producer(int arg) {
int i;for(i=0;i<30;i++){
// Produce item i here (maybe stores it in a global array)printf("Produced item %d, Total %d item(s)\n“, ...);
}}
// Thread body for consumervoid Consumer(int arg) {
int i;for(i=0;i<30;i++){
// Consume item i here (maybe retrieve it from a global array)printf(“Consumed item %d, Total %d item(s)\n“, ...);
}}
20
Producer-Consumer problem (cont.)
• Sample output:
Produced item 0, Total 1 item(s)Produced item 1, Total 2 item(s)Consumed item 0, Total 1 item(s)Consumed item 1, Total 0 item(s)Produced item 2, Total 1 item(s)Produced item 3, Total 2 item(s)Produced item 4, Total 3 item(s)Consumed item 2, Total 2 item(s)Produced item 5, Total 3 item(s)Consumed item 3, Total 2 item(s)Consumed item 4, Total 1 item(s)Produced item 6, Total 2 item(s)Consumed item 5, Total 1 item(s)Produced item 7, Total 2 item(s)Produced item 8, Total 3 item(s)Produced item 9, Total 4 item(s)Consumed item 6, Total 3 item(s)...
21
Dining Philosopher problem
• Following skeleton is an example, you can design by yourself
• A monitor-style class DiningTable:• We have 5 philosophers (0~4), which means
5 threads• Each philosopher starts at thinking, then
eating, then thinking … for 10 times• Print what a philosopher is doing when
she/he starts to do that
22
Dining Philosopher problem (cont.)
class DiningTable {public: void pickup (int it, int id) { // Philosopher “id” wants to eat for the “it”-th times printf(“%d: Philosopher %d is eating\n”, it, id); }
void putdown (int it, int id) { // Philosopher “id” goes back to think for the “it”-th times printf(“%d: Philosopher %d is thinking\n”, it, id); }}
DiningTable dining_table;// Thread body for each philosophervoid philosopher (int id) { for(int i=0; i<10; i++) { dining_table.pickup(i, id); dining_table.putdown(i, id); }}
23
Dining Philosopher problem (cont.)
• Sample output:
0: Philosopher 0 is eating0: Philosopher 0 is thinking1: Philosopher 0 is eating0: Philosopher 3 is eating0: Philosopher 3 is thinking0: Philosopher 2 is eating1: Philosopher 0 is thinking0: Philosopher 2 is thinking0: Philosopher 1 is eating0: Philosopher 1 is thinking1: Philosopher 1 is eating1: Philosopher 1 is thinking0: Philosopher 4 is eating0: Philosopher 4 is thinking2: Philosopher 0 is eating1: Philosopher 3 is eating...
24
Please do me a favor
• We all know that in a real system synchronization problems arise because threads can be interrupted at any point
• However, currently we are working in Nachos kernel, not in user programs, and we don’t call OneTick() so no interrupts would occur in our thread body implementations.
• Things will become too easy…
25
Please do me a favor (cont.)
• So, let’s make it HARD!• Please put following code into your
thread bodies, and every functions you built which may be called in thread bodies.
• This code will call kernel->currentThread->Yield() with some probability, effectively interrupts your code at any point.
26
Please do me a favor (cont.)
#define PY { if(rand()%5==0) { kernel->currentThread->Yield(); } }...class DiningTable {public: void pickup (int it, int id) {PY printf(“%d: Philosopher %d is eating\n”, it, id); }
void putdown (int it, int id) {PY printf(“%d: Philosopher %d is thinking\n”, it, id); }}...void philosopher (int id) {PY for(int i=0; i<10; i++) {PY dining_table.pickup(i, id);PY dining_table.putdown(i, id);PY }}
27
Please do me a favor (cont.)
• Please add “{ }” to all if-else and for,while loops, or this macro would mess up your program.
• You can change random seed to see different results by using flag “-rs”– ./nachos -rs 100 -PC– Please test with different random seed to
make sure that your implementations are correct
28
Some notes
• Just like Thread, Semaphore, Lock, and Condition all have a name argument in constructor: please DO NOT provide a local string to them
• You should make sure that main thread (the only thread which builds other threads) “waits” until other threads finish– How to do? This is also a synchronization
problem (an easy one)
29
Requirement
• Implement 2 synchronization problems– Make sure that no deadlock would occur– The output should be reasonable
• E.g. in first problem, following output is wrong
• E.g. in second problem, following output is wrong
Produced item 0, Total 1 item(s)Produced item 1, Total 1 item(s) # Total should be 2Consumed item 2, Total 1 item(s) # Item 2 is not generated yet
0: Philosopher 0 is eating0: Philosopher 1 is eating # Ph. 1 cannot eat because Ph. 0 is eating and holding the chopstick Ph. 1 needs
30
Requirement
• Write a 2-page report– Don’t just paste your code, I’ll read it myself– Explain why your implementations would
generate correct output, and why there is no deadlock
• If your project submission can’t compile and execute on Linux in Workstation Room 217, we will consider it as fail.– Please contact me to apply a workstation account
if you need it.
31
Submission
• Two people in one group (Write down the name and student ID of all members in the report)
• The file you need to send:1. A report in .pdf or .doc2. threads.cc, threads.h, and main.cc
• Send your files– Tar your files to an archieve named:
os_hw3_bXXXXXXXX_bOOOOOOOO.tar.gz– E-mail to [email protected] with following title:
[os_hw3] bXXXXXXXX_bOOOOOOOO– Please follow the format carefully or our auto-reply
system will not work
tar zcvf os_hw3_bXXXXXXXX_bOOOOOOOO.tar.gz report.doc other files...
32
Submission (cont.)
• Deadline: 11/10 24:00– For the delayed submission, deduct
5 points for each day
• DO NOT COPY!!Protect your code well!!