
4/18/2017 Synchronization Mechanisms &Problems Semaphores – signaling devices 7H. Semaphores when direct communication was not an option e.g. between villages, ships, trains 7I. Producer/Consumer Problems 7J. Object Level Locking 7K. Bottlenecks, Contention and Granularity Synchronization Mechanisms and Problems 1 Semaphores - History Semaphores - Operations • Concept introduced in 1968 by Edsger Dijkstra • Semaphore has two parts: – cooperating sequential processes – an integer counter (initial value unspecified) • THE classic synchronization mechanism – a FIFO waiting queue – behavior is well specified and universally accepted • P (proberen/test) ... “wait” – a foundation for most synchronization studies – decrement counter, if count >= 0, return – a standard reference for all other mechanisms – if counter < 0, add process to waiting queue • more powerful than simple locks • V (verhogen/raise) ... “post” or “signal” – they incorporate a FIFO waiting queue – increment counter – they have a counter rather than a binary flag – if counter >= 0 & queue non-empty, wake 1 st proc Synchronization Mechanisms and Problems 3 Synchronization Mechanisms and Problems 4 using semaphores for exclusion Semaphores - for exclusion struct account { • initialize semaphore count to one struct semaphore s; /* initialize count to 1, queue empty, lock 0 */ int balance; count reflects # threads allowed to hold lock … – }; • use P/wait operation to take the lock int write_check( struct account *a, int amount ) { int ret; – the first will succeed p( &a->semaphore ); /* get exclusive access to the account */ if ( a->balance >= amount ) { /* check for adequate funds */ – subsequent attempts will block amount -= balance; ret = amount; • use V/post operation to release the lock } else ret = -1; – restore semaphore count to non-negative v( &a->semaphore ); /* release access to the account */ return( ret ); – if any threads are waiting, unblock the first in line } Synchronization Mechanisms and Problems 5 Synchronization Mechanisms and Problems 6 1 4/18/2017 using semaphores for notifications Semaphores - completion events struct semaphore pipe_semaphore = { 0, 0, 0 }; /* count = 0; pipe empty */ • initialize semaphore count to zero char buffer[BUFSIZE]; int read_ptr = 0, write_ptr = 0; char pipe_read_char() { – count reflects # of completed events p (&pipe_semaphore ); /* wait for input available */ c = buffer[read_ptr++]; /* get next input character */ • use P/wait operation to await completion if (read_ptr >= BUFSIZE) /* circular buffer wrap */ read_ptr -= BUFSIZE; return(c); – if already posted, it will return immediately } – else all callers will block until V/post is called void pipe_write_string( char *buf, int count ) { while( count-- > 0 ) { • use V/post operation to signal completion buffer[write_ptr++] = *buf++; /* store next character */ if (write_ptr >= BUFSIZE) /* circular buffer wrap */ write_ptr -= BUFSIZE; – increment the count v( &pipe_semaphore ); /* signal char available */ } – if any threads are waiting, unblock the first in line } • one signal per wait: no broadcasts Synchronization Mechanisms and Problems 7 Synchronization Mechanisms and Problems 8 Counting Semaphores Implementing Semaphores • initialize semaphore count to ... void sem_wait(sem_t *s) { pthread_mutex_lock(&s->lock); – count reflects # of available resources while (s->value <= 0) • use P/wait operation to consume a resource pthread_cond_wait(&s->cond, &s->lock); s->value--; – if available, it will return immediately pthread_mutex_unlock(&s->lock); – else all callers will block until V/post is called } void sem_post(sem_t *s) { • use V/post operation to produce a resource pthread_mutex_lock(&s->lock); – increment the count s->value++; pthread_cond_signal(&s->cond); – if any threads are waiting, unblock the first in line pthread_mutex_unlock(&s->lock) • one signal per wait: no broadcasts } Synchronization Mechanisms and Problems 9 Synchronization Mechanisms and Problems 10 Implementing Semaphores in OS (locking to solve sleep/wakeup race) void sem_wait(sem_t *s ) { for (;;) { • requires a spin-lock to work on SMPs save = intr_enable( ALL_DISABLE ); while( TestAndSet( &s->lock ) ); – sleep/wakeup may be called on two processors if (s->value > 0) { – the critical section is short and cannot block s->value--; void sem_post(struct sem_t *s) { s->sem_lock = 0; struct proc_desc *p = 0; – we must spin, because we cannot sleep ... the lock we intr_enable( save ); save = intr_enable( ALL_DISABLE ); need is the one that protects the sleep operation return; while ( TestAndSet( &s->lock ) ); } s->value++; • also requires interrupt disabling in sleep add_to_queue( &s->queue, myproc ); if (p = get_from_queue( &s->queue )) { myproc->runstate |= PROC_BLOCKED; p->runstate &= ~PROC_BLOCKED; – wakeup is often called from interrupt handlers s->lock = 0; } intr_enable( save ); s->lock = 0; – interrupt possible during sleep/wakeup critical section yield(); intr_enable( save ); – If spin-lock already is held, wakeup will block for ever } if (p) } reschedule( p ); • very few operations require both of these } Synchronization Mechanisms and Problems 11 Synchronization Mechanisms and Problems 12 2 4/18/2017 Limitations of Semaphores Using Condition Variables • semaphores are a very spartan mechanism pthread_mutex_t lock = PTHEAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHEAD_COND_INITIALIZER; – they are simple, and have few features … – more designed for proofs than synchronization pthread_mutex_lock(&lock); • they lack many practical synchronization features while (ready == 0) pthread_cond_wait(&cond, &lock); – It is easy to deadlock with semaphores pthread_mutex_unlock(&lock) – one cannot check the lock without blocking … – they do not support reader/writer shared access if (pthread_mutex_lock(&lock)) { ready = 1; – no way to recover from a wedged V'er pthread_cond_signal(&cond); – no way to deal with priority inheritance pthread_mutex_unlock(&lock); • none the less, most OSs support them } Synchronization Mechanisms and Problems 13 Synchronization Mechanisms and Problems 14 Bounded Buffer Problem w/CVs Producer/Consumer w/Semaphores void producer( FIFO *fifo, char *msg, int len ) { void producer( FIFO *fifo, char *msg, int len ) { for( int i = 0; i < len; i++ ) { for( int i = 0; i < len; i++ ) { pthread_mutex_lock(&mutex); sem_wait(&empty); while (fifo->count == MAX) sem_wait(&mutex); pthread_cond_wait(&empty, &mutex); put(fifo, msg[i]); put(fifo, msg[i]); pthread_cond_signal(&fill); sem_post(&mutex); pthread_mutex_unlock(&mutex); sem_post(&full); } } void consumer( FIFO *fifo, char *msg, int len ) { void consumer( FIFO *fifo, char *msg, int len ) { } } for( int i = 0; i < len; i++ ) { for( int i = 0; i < len; i++ ) { pthread_mutex_lock(&mutex); sem_wait(&full); while (fifo->count == 0) sem_wait(&mutex); pthread_cond_wait(&fill, &mutex); msg[i] = get(fifo); msg[i] = get(fifo); pthread_cond_signal(&empty); sem_post(&mutex); pthread_mutex_unlock(&mutex); sem_post(&empty); } } } } Synchronization Mechanisms and Problems 15 Synchronization Mechanisms and Problems 16 Object Level Locking Whole File Locking • mutexes protect code critical sections int flock( fd , operation ) – brief durations (e.g. nanoseconds, milliseconds) • supported operation s: – other threads operating on the same data – LOCK_SH … shared lock (multiple allowed) – all operating in a single address space – LOCK_EX … exclusive lock (one at a time) • persistent objects are more difficult – LOCK_UN … release a lock – critical sections are likely to last much longer • lock is associated with an open file descriptor – many different programs can operate on them – lock is released when that file descriptor is closed – may not even be running on a single computer • locking is purely advisory • solution: lock objects (rather than code) – does not prevent reads, writes, unlinks Synchronization Mechanisms and Problems 17 Synchronization Mechanisms and Problems 18 3 4/18/2017 Advisory vs Enforced Locking Ranged File Locking • Enforced locking int lockf(fd , cmd, offset, len ) – done within the implementation of object methods • supported cmds : – guaranteed to happen, whether or not user wants it – F_LOCK … get/wait for an exclusive lock – may sometimes be too conservative – F_ULOCK … release a lock • Advisory locking – F_TEST/F_TLOCK … test, or non-blocking request – a convention that “good guys” are expected to follow – offset/len specifies portion of file to be locked – users expected to lock object before calling methods • lock is associated with a file descriptor – gives users flexibility in what to lock, when – lock is released when file descriptor is closed – gives users more freedom to do it wrong (or not at all) • locking may or may not be enforced – mutexes are advisory locks – depending on the underlying file system Synchronization Mechanisms and Problems 19 Synchronization Mechanisms and Problems 20 Cost of not getting a Lock Probability of Conflict • protect critical sections to ensure correctness • many critical sections are very brief – in and out in a matter of nano-seconds • blocking is much more (e.g. 1000x) expensive – micro-seconds to yield, context switch – milliseconds if swapped-out or a queue forms • performance depends on conflict probability Cexpected = (Cget * (1-Pconflict )) + (Cblock * Pconflict ) Synchronization Mechanisms and Problems 21 Synchronization Mechanisms and Problems 22 Convoy Formation Performance: resource convoys • in general threads-1 Pconflict = 1 – (1 – (Tcritical / Ttotal )) (nobody
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages7 Page
-
File Size-