Class Announcement TA is expected to add/move office hours to tomorrow for Project 0 Project 0 deadline is extended to next Monday April 13 noon. A copy.
Post on 30-Dec-2015
214 Views
Preview:
Transcript
Class Announcement
• TA is expected to add/move office hours to tomorrow for Project 0
• Project 0 deadline is extended to next Monday April 13 noon.
• A copy of the text book reserved in the library.
• Any Issues for Project 0? Pass all public tests locally and then fail in
submit.cs?
Testfile2 without/with an invalid command
ls -l > tempwc templs -l -f > tempwc < temp > temp2sort < temp > temp3cat temp2diff temp2 temp3 > temp4wc temp4exit
ls -l > tempwc templs -l -f > tempwc < temp > temp2sort < temp > temp3catt temp2diff temp2 temp3 > temp4wc temp4exit
Testfile4 without/with an invalid command
ls -l -f | sort > templs -l | sort > temp1diff temp temp1 > temp2cat < temp | uniq | sort > temp3diff temp3 temp |sort | wc > temp4cat temp4exit
ls -l -f | sort > templs -l | sort > temp1diff temp temp1 > temp2cat < temp | uniq | sort > temp3catt temp3 | wcdiff temp3 temp |sort | wc > temp4cat temp4exit
Autograding only compares with expected answers for processing all valid commands. Donot test weird cases.
Topics
• The critical-section problem and examples
• Solutions Locks Semaphores Condition variables (monitors).
• Synchronization in Nachos and Pthreads
Shared variables in a producer/consumer program
count -- number of items available in -- points to the writeable slot out -- points to the slot to read
in out
Producer Thread Code
while (true) {
while (count == BUFFER_SIZE) ;
// buffer is full, spin
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
}
in
Consumer thread
while (true) {
while (count == 0) ; // Nothing is available. Spin
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
}
out
Race Conditions: Example
Count--;
Producer thread Consumer thread
Count++;
Count=5
Is count still 5?
Race Conditions: two or more processes (threads) are reading and writing on shared data and the final result depends on who runs precisely & when
Review compiled code
Count—: register2 = count register2 = register2 - 1 count = register2
Producer thread Consumer thread
Count++: register1 = count register1 = register1 + 1 count = register1
Count=5
Is count still 5?
Executing compiled code
Count—:
register2 = count register2 = register2 - 1 count = register2
Producer thread Consumer thread
Count++: register1 = count register1 = register1 + 1 count=register1
Count=5
Time Is count still 5? 4, 6?Is count still 5? 4, 6?
Executing compiled code
Count—: register2 = count
register2 = register2 - 1
count = register2
Producer thread Consumer thread
Count++: register1 = count
register1 = register1 + 1
count = register1
Count=5
Is count still 5? 4, 6?Is count still 5? 4, 6?Time
Critical-Section Management
Critical section: the part of the program where shared variables are accessed
Property of Critical-Section Solutions
1.Mutual Exclusion – Only one can enter the critical section. Safety property in AD book
2.Progress - If some processes wish to enter their critical section and nobody is in the critical section, then one of them will enter in a limited time. Liveness property in AD book
3.Bounded Waiting - If one process starts to wait for entering an critical section, there is a limit on the number of times other processes entering the section before this process enters. Liveness property in AD book
Acquire lock
Critical section
Release lock
Lock for Critical-section Problem
•Thread waits if there is a lock.•It enters the critical after acquiring a lock.•Only the thread who locks can unlock.
Nachos Lock Interface
• Lock can be in one of two states: locked or unlocked
• class Lock {
public:
Lock (char *name);
//create a lock with unlocked state
~Lock();
void Acquire(); //Atomically waits until the lock is unlocked, and then sets the lock to be locked.
void Release(); //Atomically changes the state to be unlocked. Only the thread who owns the lock can release.
}
How to use locks
• Typically associate a lock with a piece of shared data for mutual execlusion.
• When a thread needs to access, it first acquires the lock, and then accesses data. Once access completes, it releases the lock.
Example
Lock *k= new Lock (“Lock”);
k->Acquire();
Perform critical section operations.
k->Release();
}
Synchronization with Locks: Example
int a=0;Lock *k;void sum (int p){ int c; k->Acquire();
a=a+1;c=a;k->Release()printf(“%d : a= %d\n”, p,c);
}
void main() {
Thread *t=new Thread (“Child”);
k=new Lock(“Lock”);
t->Fork(sum,1);
sum(0);
}
Semaphore for the critical-section problem
• Semaphore S – nonnegative integer variable• Can only be accessed /modified via two indivisible
(atomic) operations wait (S) { //also called P() while S <= 0
; // wait in a queue S--; } signal (S) { //also called V() //wake up some waiting thread S++; }
Semaphore
• Counting semaphore – initial value representing how many threads can be in the critical section. Binary semaphore (also known as mutex locks) – integer value
ranged between 0 and 1.• Provides mutual exclusion
Semaphore mutex; // initialized to 1
do {
P(mutex);
// Critical Section
V(mutex);
} while (TRUE);• Not recommended by the AD text book (Chapter 5.8), but still
widely used.
Semaphores in Nachos
• class Semaphore{
public:
Semaphore (char *name, int counter);
// initial counter value
~Semaphore();
void P(); //Atomically waits until the counter is greater than 0 and then decreases the counter
void V(); //Atomically increases the counter
}
Synchronization with Semaphore: Example
int a=0;Semaphore *s;void sum (int p){ int c; s->P();
a=a+1;c=a;s->V();printf(“%d : a= %d\n”, p,c);
}
void main() {
Thread *t=new Thread (“Child”);
s=new Semaphore(“S”,1);
t->Fork(sum,1);
sum(0);
}
Synchronization in Consumer thread
while (true) {
while (count == 0) ; // sping waiting
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use data for other things
}
out
Synchronization in Producer/ Consumer threads
Consumer loop:
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use data and do others
Producer loop:
Produce next item
while (count == BUFFER_SIZE) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
out
What is shared?How to synchronize?
count
in
Synchronization AttemptConsumer loop:
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use dataProducer loop:
Produce next item
while (count == BUFFER_SIZE) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
out
incount
Deadlock?How to avoid spin?
Another Synchronization AttemptConsumer loop:
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use dataProducer loop:
Produce next item
while (count == BUFFER_SIZE) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
out
incount
Mutual execution?
in
What can happen with this trace?
Consumer 1 :
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Do other things
out
incount
in
Consumer 2:
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use data and do others
Semaphore for consumer/producer problem
• Simplify the problem: Unbounded buffer Worry about bounded buffer constraint later
• Condition to check: Is there a data item available to consume? Not available? Wait using 1 semaphore
Semaphore for consumer-producer problem with unbounded buffer
Semaphore *data =new Semaphore(“Data”, 0);– Indicate # of data items available for consuming
Consumer thread: while(1) {
data-> P(); //wait until an item is available
Use data item;}
Producer thread: while(1){
produce next item;data->V(); //notify an item is available
}
Semaphore can do more than mutual exclusion, and can synchronize a consumer/producer pipe
Semaphore for consumer/producer problem with bounded buffer
What condition to check for bounded buffer?
Conditions to check: Is there a data item available to consume? Is there space available to produce a data
item? Wait using two semaphores
Consumer-producer problem with bounded buffer
• Two semaphores: Semaphore *data =new Semaphore(“Data”, 0);
– Indicate # of data items available for consuming Semaphore *space =new Semaphore(“Space”, 10); Indicate # of 10 data slots available.
Producer thread:
while(1){
produce next item;
data->V(); //notify item is available
}
Consumer-producer problem with bounded buffer
• Two semaphores: Semaphore *data =new Semaphore(“Data”, 0);
– Indicate # of data items available for consuming Semaphore *space =new Semaphore(“Space”, 10); Indicate # of 10 data slots available.
Producer thread:
while(1){
space->P();//wait until space is available
produce next item;
data->V(); //notify data is available
}
Consumer-producer problem with bounded buffer
Semaphore *data =new Semaphore(“Data”, 0); Semaphore *space =new Semaphore(“Space”, 10); Producer thread:
while(1){
space->P();//wait until space is available
produce next item;
data->V(); //notify data is available
} Consumer thread:
while(1){
data->P();//wait until data is available
consume next item;
}
Consumer-producer problem with bounded buffer
Semaphore *data =new Semaphore(“Data”, 0); Semaphore *space =new Semaphore(“Space”, 10); Producer thread:
while(1){
space->P();//wait until space is available
produce next item;
data->V(); //notify data is available
} Consumer thread:
while(1){
data->P();//wait until data is available
consume next item;
space->V();//notify space is available
}
Synchronization for pthreads: Mutex
pthread_mutex_t mutex; const pthread_mutexattr_t attr;int status;
status = pthread_mutex_init(&mutex,&attr);
status = pthread_mutex_destroy(&mutex);
status = pthread_mutex_unlock(&mutex);
status = pthread_mutex_lock(&mutex); - block
Thread i
……lock(mutex)……critical region……unlock(mutex)……
Semaphore for Pthreads
int status,pshared;
sem_t sem;
unsigned int initial_value;
status = sem_init(&sem,pshared,initial_value);
status = sem_destroy(&sem);
status = sem_post(&sem);
status = sem_wait(&sem);
What now?Consumer loop:
while (count == 0) ;
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
Use dataProducer loop:
Produce next item
while (count == BUFFER_SIZE) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
out
incount
How to use semaphore with lock?
Synchronization with semaphoreConsumer loop:
data->P();
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
space->V();
Use dataProducer loop:
Produce next item
space->P();//wait until space is available) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
data->V(); //notify data is available
Synchronization with semaphore/lock?Consumer loop:
data->P();
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
space->V();
Use dataProducer loop:
Produce next item
space->P();//wait until space is available) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
data->V(); //notify data is available
What happens when a consumer does not hod a lock after waking up from data->p()?
Consumer 1:
data->P();
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
space->V();
Use data
Consumer 2:
data->P();
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
space->V();
Use data
Synchronization with semaphore/lock?Consumer loop:
data->P();
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
space->V();
Use dataProducer loop:
Produce next item
space->P();//wait until space is available) ;
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
data->V(); //notify data is available
How to hold a lock immediately after waking up?
Condition Variables in Nachos• Pair it with a lock
• class Condition {
public:
Condition(char *name);
~Condition();
void Wait(Lock *mylock); //Atomically releases the lock and waits. When it is returned, the lock is reacquired again.
void Signal(Lock *myLock); //Wake up one waiting thread to run. The lock is not released.
void Broadcast(Lock *myLock); //Wake up all threads waiting on the condition. The lock is not released.
}
Condition Variables for consumer-producer problem with unbounded buffer
• int avail=0; // # of data items available for consumption• Lock *L; Condition *cv= new Condition (“condition”);• Consumer thread loop:
L.Acquire();if (avail <=0) cv.Wait(L);
Fetch next item; avail = avail-1;L.Release();Do other things
Producer thread loop: L.Acquire();Add next item; avail = avail+1; cv.Signal(L); //notify an item is availableL.Release();Do other things
Can conditionstill be true afterwake-up?How to protect?
Condition Variables for consumer-producer problem with unbounded buffer
• int avail=0; // # of data items available for consumption• Lock *L; Condition *cv= new Condition (“condition”);• Consumer thread loop:
L.Acquire();while(avail <=0) cv.Wait(L);
Fetch next item; avail = avail-1;L.Release();Do other things
Producer thread loop: L.Acquire();Add next item; avail = avail+1; cv.Signal(L); //notify an item is availableL.Release();Do other things
Thread 1
mylock.Acquire();
When condition is not satisfied,
cv.Wait(mylock);
Critical Section;
mylock.Release(); Thread 2:
mylock.Acquire();
When condition can satisfy,
cv.Signal(mylock);
mylock.Relase();
How to Use Condition Variables: Typical Flow
When to use condition broadcast()?
• When waking up one thread to run is not sufficient.
• Example: concurrent malloc()/free() for allocation and deallocation of objects with non-uniform sizes.
malloc()/free() with condition broadcast• Initially 10 bytes are free. • m() stands for malloc(). f() for free()
Thread 1:
m(10) – succ
f(10) –broadcast?
m(7) – wait
Resume m(7)-wait
Thread 2:
m(5) – wait
Resume m(5)-succ
f(5) –broadcast?
Thread 3:
m(5) – wait
Resume m(5)-succ
m(3) –wait
Resume m(3)-succ
malloc()/free() with condition signal• Initially 10 bytes are free. • m() stands for malloc(). f() for free()
Thread 1:
m(10) – succ
f(10) –signal?
m(7) – wait
Resume m(7)-wait
Thread 2:
m(5) – wait
Resume m(5)-succ
f(5) –signal?
Thread 3:
m(5) – wait
Resume m(5)-succ
m(3) –wait
Resume m(3)-succ
Pthread synchronization: Condition variables
int status;
pthread_condition_t cond;
const pthread_condattr_t attr;
pthread_mutex mutex;
status = pthread_cond_init(&cond,&attr);
status = pthread_cond_destroy(&cond);
status = pthread_cond_wait(&cond,&mutex);
status = pthread_cond_signal(&cond);
status = pthread_cond_broadcast(&cond);
Summary
• Concurrent threads are a very useful abstraction Allow transparent overlapping of computation and I/O Allow use of parallel processing when available
• Concurrent threads introduce problems when accessing shared data Programs must be insensitive to arbitrary interleaving Without careful design, shared variables can become
completely inconsistent• Synchronization with lock, condition variables, &
semaphores
top related