Download presentation
Presentation is loading. Please wait.
Published byDarleen Rogers Modified over 7 years ago
1
Auburn University http://www.eng.auburn.edu/~xqin
COMP Introduction to Operating Systems Project 3 – Synchronization Cats and Mice: Implementation Dr. Xiao Qin Auburn University
2
Review: Semaphores and Variables
volatile bool all_dishes_available = true; semaphore done = 0; semaphore mutex = 1; semaphore dish_mutex = 1; semaphore cats_queue = 0; volatile int cats_wait_count = 0; volatile bool no_cat_eat = true; /*first cat*/ semaphore mice_queue = 0; volatile int mice_wait_count = 0; volatile bool no_mouse_eat = true; The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
3
First Cat and No Mouse wait(mutex);
if (all_dishes_available == true) { all_dishes_availalbe = false; signal(cats_queue); /* let first cat in */ } cats_wait_count++; signal(mutex); wait(cats_queue); /*first cat in, other wait*/ if (no_cat_eat == true) {/*no_cat_eat:global*/ no_cat_eat = false; first_cat_eat = true;/*first_cat_eat:local*/ else first_cat_eat = false; The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
4
How does the first cat control the kitchen?
if (first_cat_eat == true) { wait(mutex); if (cat_wait_count > 1) { another_cat_eat = true; signal(cats_queue); /*let another cat in*/ } signal(mutex); kprintf(“Cat in the kitchen.\n”); /*cat name*/ The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
5
All cats (first cat and non-first cat) in the kitchen.
wait(dish_mutex); /*protect shared variables*/ if (dish1_busy == false) { dish1_busy = true; mydish = 1; } else { assert(dish2_busy == false); dish2_busy = true; mydish = 2; signal(dish_mutex); kprint(“Cat eating.\n”); /* cat name */ clocksleep(1); /* enjoys food */ kprint(“Finish eating.\n”); /* done. */ The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
6
All cats (first cat and non-first cat) release dishes.
wait(dish_mutex); /*protect shared variables*/ if (mydish == 1) /* release dish 1 */ dish1_busy = false; else /* release dish 2 */ dish2_busy = false; signal(dish_mutex); wait(mutex); /*protect shared variables*/ cat_wait_count--; /*reduced before leaving*/ signal(mutex); The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
7
First cat is leaving the kitchen.
if (first_cat_eat == true) { /* first cat */ if (another_cat_eat == true) wait(done); /* wait for another cat */ kprintf(“First cat is leaving.\n”); no_cat_eat = true; /*let next cat control*/ /* Switch to mice if any is waiting */ /* (1) Wake up mice */ /* (2) Wake up cat */ /* (3) set all_dishes_available to true */ The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
8
How to wake up waiting mice or cats?
/* Switch to mice if any is waiting */ wait(mutex); /* protect shared variables */ if (mice_wait_count > 0) /* mice waiting */ signal(mice_queue); /* let mice eat */ else if (cats_wait_count > 0) signal(cats_queue); /* let cat eat */ else all_dishes_availalbe = true; signal(mutex); } /* end of first_cat_eat */ else { /* non-first cat is leaving */ kprintf(“Non-first cat is leaving\n”); signal(done); /* inform the first cat */ } The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times. C does not support bool #define true 1 #define false 0 typedef char bool;
9
Semaphore in OS/161 /* kern/include/synch.h */ struct semaphore {
char *name; volatile int count; }; struct semaphore* sem_create(const char *name, int initial_count); void sem_destroy(struct semaphore *); void P(struct semaphore *); void V(struct semaphore *); /* Implemented in kern/thread/synch.c */ The Semaphore mechanism has been implemented in OS/161. Use the source code of semaphore as a good example for the implementation of locks and condition variables.
10
Semaphore: Sample Usage
/* Declare a semaphore */ static semaphore *sample_sm; /* Initialize the semaphore */ sample_sm = sem_create(“sample semaphore", 0); if (sample_sm == NULL) { panic(”sample_sm: Out of memory.\n"); } /* Destroy the semaphore in the end */ sem_destroy(sample_sm); sample_sm = NULL; P(done); /* Wait for “done” */ V(done); /* Signal “done” */ /* static can limit the scope of global variable to only the file it is declared in */ "static" can be used to limit the scope of global variable to only the file it is declared in.
11
Locks in OS/161 /* kern/include/synch.h */ struct lock { char *name;
/* add what you need here. How? */ }; struct lock *lock_create(const char *name); void lock_acquire(struct lock *); void lock_release(struct lock *); int lock_do_i_hold(struct lock *); void lock_destroy(struct lock *); struct thread *volatile holder; struct lock { char *name; // add what you need here // (don't forget to mark things volatile as needed) };
12
Lock: Sample Usage /* Declare a lock */
Static struct lock *sample_mutex; /* Initialize the lock */ sample_mutex = lock_create(”sample mutex"); if (sample_mutex == NULL) panic(”sample_mutex: Out of memory.\n"); /* Destroy the lock in the end */ lock_destroy(sample_mutex); sample_mutex = NULL; lock_acquire(sample_mutex); /* Acquire */ lock_release(sample_mutex); /* Release */
13
Implementing lock_acquire()
void lock_acquire(struct lock *lock) { turn off interrupts; /*see P(*sem) in next slide*/ if (lock_do_i_hold(lock)) /* check deadlock */ panic("lock %s at %p: Deadlock.\n", lock->name, lock); /* wait the lock to become free */ while (lock’s holder != NULL) { sleep this thread; /*see P(*sem) in next slide*/ } /* this thread is holding the lock */ lock’s holder is set to curthread; turn on interrupts to the previous level;
14
How to sleep the current thread?
void P(struct semaphore *sem) { int spl; assert(sem != NULL); spl = splhigh(); while (sem->count==0) { thread_sleep(sem); } assert(sem->count>0); sem->count--; splx(spl); Check input argument Turn off interrupts ‘sem’ is a mark or indicator Turn on interrupts
15
How to wakeup a thread? void V(struct semaphore *sem) { int spl;
assert(sem != NULL); spl = splhigh(); sem->count++; assert(sem->count>0); thread_wakeup(sem); splx(spl); } Check input argument Turn off interrupts ‘sem’ is a mark or indicator Turn on interrupts
16
How to implement lock_do_i_hold?
int lock_do_i_hold(struct lock *lock) { int spl, same; use assert() to input argument lock; Turn off interrupts; if (lock->holder is the same as this thread) set same to 1; /* true */ else set same to 0; /* false */ Turn on interrupts to previous level; /* 1 means lock is held by this thread */ return same; } Is lock held by this thread? lock != NULL This thread = curthread
17
Condition Variables: Data Structure
Wait until a variable meets a particular condition There is no actual variable in the CV /* kern/include/synch.h */ struct cv { char *name; // add what you need here }; There is little information on condition variables in the textbook
18
Condition Variables: Functions
struct cv *cv_create(const char *name); void cv_destroy(struct cv *); /* Release lock, put thread to sleep until cv is signaled; when thread wakes up again, re-acquire lock before returning */ void cv_wait(struct cv *cv, struct lock *lock); /* If any threads are waiting on cv, wake up one of them. Caller must hold lock, which must be the same as the lock used in the wait call */ void cv_signal(struct cv *cv, struct lock *lock); /* Same as signal, except wake up all waiting threads */ void cv_broadcast(struct cv *cv, struct lock *lock); References: Operations: cv_wait Release the supplied lock, go to sleep, and, after waking up again, re-acquire the lock. cv_signal - Wake up one thread that's sleeping on this CV. cv_broadcast - Wake up all threads sleeping on this CV.
19
Producer/Consumer Implementation with Locks
char buffer[SIZE]; int count = 0, head = 0, tail = 0; static struct lock *mutex; mutex = lock_create(“mutex for cv”); void producer(char c) { lock_acquire(mutex); count++; buffer[head] = c; head++; if (head == SIZE) { head = 0; } lock_release(mutex); char consumer() { char c; lock_acquire(mutex); count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; } lock_release(mutex); return c; Let’s consider the producer/consumer sample to show how to use condition variables We start this example with locks. 3. No need to use static here; just a demonstration
20
How to handle the empty/full cases using locks?
void producer(char c) { lock_acquire(mutex); while (count == SIZE) { lock_release(mutex); } count++; buffer[head] = c; head++; if (head == SIZE) head = 0; char consumer() { char c; lock_acquire(mutex); while (count == 0) { lock_release(mutex); } count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; return c; Which lock_acqure and lock_release are a pair? Which lock_acqure() and lock_release() are a pair?
21
How to implement cv_wait()?
void cv_wait(struct cv *cv, struct lock *lock) { use assert to check input cv and lock; turn off interrupts; release the lock; /* thread_sleep() using cv or lock? */ sleep the thread until someone signals cv; acquire the lock; turn on interrupts to the previous level; } cv shouldn’t be NULL lock shouldn’t be NULL
22
How to implement cv_signal()?
void cv_signal(struct cv *cv, struct lock *lock) { use assert to check cv and lock; turn off interrupts; /* !lock_do_i_hold(lock) */ if (this thread does not hold lock) panic("cv_signal error: cv %s at %p, lock %s at %p.\n", cv->name, cv, lock->name, lock); /* see also how to wakeup a thread Slide 15 */ wakeup one thread using indicator “cv”; turn on interrupts to the previous level; } cv shouldn’t be NULL lock shouldn’t be NULL
23
Condition Variables: Sample Usage
/* Declare a cv */ static struct cv *sample_cv; /* Initialize the cv */ sample_cv = cv_create(”sample cv"); if (sample_cv == NULL) panic(”sample_cv: Out of memory.\n"); /* Destroy the cv in the end */ cv_destroy(sample_cv); sample_cv = NULL; cv_wait(sample_cv, sample_lock); /* Wait */ cv_signal(sample_cv, sample_lock); /*Signal*/
24
Producer/Consumer How to use condition variables in OS/161?
char buffer[SIZE]; int count = 0, head = 0, tail = 0; static struct lock *mutex; static struct cv *notEmpty; static struct cv *notFull; mutex = lock_create(“mutex for cv”); if (mutex == NULL) panic(”mutex: Out of memory.\n"); notEmpty = cv_create(“Buffer not empty”); notFull = cv_create(“Buffer not full”); if (notEmpty == NULL || notFull == NULL) panic(”CV: Out of memory.\n"); Which lock_acqure and lock_release are a pair?
25
Producer: how to use condition variables in OS/161?
void producer(char c) { lock_acquire(mutex); while (count == SIZE) { cv_wait(notFull, mutex); } count++; buffer[head] = c; head++; if (head == SIZE) { head = 0; cv_signal(notEmpty, mutex); lock_release(mutex);
26
Consumer: how to use condition variables in OS/161?
char consumer() { char c; lock_acquire(mutex); while (count == 0) { cv_wait(notEmpty, mutex); } count--; c = buffer[tail]; tail++; if (tail == SIZE) { tail = 0; cv_signal(notFull, mutex); lock_release(mutex); return c;
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.