Title: Nachos Project 3
1Nachos Project 3
- Lecturer Hao-Hua Chu
- TA Chun-Po Wang (Artoo)
- Date 2008/10/25
2Project 3
- Practice thread synchronization
- Producer-consumer problem
- Dining philosophers problem
- Implement these problems with Nachos thread and
synchronization routines
3Summary
- Motivation Objective
- Synchronization Problems
- Nachos Synchronization Routines
- Semaphore
- Lock
- Condition
- Requirement
- Submission
4Motivation 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
5Synchronization 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 wont put data into buffer when its
full - consumer wont remove data from en empty buffer
- the state of buffer is consistent after each
action
Buffer
Producer
Consumer
6Producer-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 wont access it when
another is working on it. - Or, the data may be corrupted
7Synchronization 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, arent they?)
http//en.wikipedia.org/wiki/ImageDining_philosop
hers.png
8Dining 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
9Nachos 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
10Semaphore class
- int value // value gt 0
- P() waits until value gt 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
11Lock 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 SemaphoreP()) - Release() release the lock and wake up a thread
waiting on this lock (by calling SemaphoreV()) - However, only the thread which acquired the lock
can release it - This is different to a semaphore
12An example
- See class SynchConsoleOutput (code/userprog/synchc
onsole.cc)
void SynchConsoleOutputPutChar(char ch)
lock-gtAcquire() consoleOutput-gtPutChar(ch)
waitFor-gtP() lock-gtRelease() void
SynchConsoleOutputCallBack()
waitFor-gtV()
13Monitor
- 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
14Monitor example
- Following pseudo code demonstrate a channel which
can only store one integer value at a time
function receive() var int received
while not full do wait(snd) received
contents full false notify(rcv)
return received //End of monitor
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)
Source http//en.wikipedia.org/wiki/Monitor_(sync
hronization)
15Condition 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
16Condition 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
17Implementation
- Implements producer-consumer problem with
semaphores and locks (built by Nachos) - Implements dining philosopher problem with a
monitor-style class (built by you)
18Implementation (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
19Producer-Consumer problem
- Produce and consume 30 items 029
- 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 producer void Producer(int
arg) int i for(i0ilt30i) // Produce
item i here (maybe stores it in a global
array) printf("Produced item d, Total d
item(s)\n, ...) // Thread body for
consumer void Consumer(int arg) int
i for(i0ilt30i) // Consume item i here
(maybe retrieve it from a global
array) printf(Consumed item d, Total d
item(s)\n, ...)
20Producer-Consumer problem (cont.)
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) ...
21Dining Philosopher problem
- Following skeleton is an example, you can design
by yourself - A monitor-style class DiningTable
- We have 5 philosophers (04), 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
22Dining 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
philosopher void philosopher (int id)
for(int i0 ilt10 i)
dining_table.pickup(i, id)
dining_table.putdown(i, id)
23Dining Philosopher problem (cont.)
0 Philosopher 0 is eating 0 Philosopher 0 is
thinking 1 Philosopher 0 is eating 0
Philosopher 3 is eating 0 Philosopher 3 is
thinking 0 Philosopher 2 is eating 1
Philosopher 0 is thinking 0 Philosopher 2 is
thinking 0 Philosopher 1 is eating 0
Philosopher 1 is thinking 1 Philosopher 1 is
eating 1 Philosopher 1 is thinking 0
Philosopher 4 is eating 0 Philosopher 4 is
thinking 2 Philosopher 0 is eating 1
Philosopher 3 is eating ...
24Please 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 dont call
OneTick() so no interrupts would occur in our
thread body implementations. - Things will become too easy
25Please do me a favor (cont.)
- So, lets 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-gtcurrentThread-gtYield(
) with some probability, effectively interrupts
your code at any point.
26Please do me a favor (cont.)
define PY if(rand()50)
kernel-gtcurrentThread-gtYield() ... 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 i0 ilt10
i) PY dining_table.pickup(i, id) PY
dining_table.putdown(i, id) PY
27Please 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
28Some 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)
29Requirement
- 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 2 Consumed item
2, Total 1 item(s) Item 2 is not generated yet
0 Philosopher 0 is eating 0 Philosopher 1 is
eating Ph. 1 cannot eat because Ph. 0
is eating and holding the
chopstick Ph. 1 needs
30Requirement
- Write a 2-page report
- Dont just paste your code, Ill read it myself
- Explain why your implementations would generate
correct output, and why there is no deadlock - If your project submission cant 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.
31Submission
- Two people in one group (Write down the name and
student ID of all members in the report) - The file you need to send
- A report in .pdf or .doc
- threads.cc, threads.h, and main.cc
- Send your files
- Tar your files to an archieve namedos_hw3_bXXXXX
XXX_bOOOOOOOO.tar.gz - E-mail to artoo_at_csie.ntu.edu.tw with following
titleos_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...
32Submission (cont.)
- Deadline 11/10 2400
- For the delayed submission, deduct 5 points for
each day - DO NOT COPY!!Protect your code well!!