Lecture 9: Thread Synchronizations

Lecture 9: Thread Synchronizations

Lecture 9: Thread Synchronizations Fall 2018 Jason Tang Slides based upon Operating System Concept slides, http://codex.cs.yale.edu/avi/os-book/OS9/slide-dir/index.html Copyright Silberschatz, Galvin, and Gagne, 2013 "1 Topics • Mutex Locks! • Semaphores! • Deadlocks "2 Mutex Locks • test_and_set() and compare_and_swap() are hardware specific, and are abstracted by threading libraries! • mutual exclusion lock (mutex): Simplest general-purpose synchronizer! • Protects a critical section by first acquire() a lock, and then release() the lock! • acquire() and release() must be atomic, usually implemented via hardware atomic instructions (x86’s CMPXCHG, ARM’s LDREX/STREX) "3 Mutex Pseudocode mutex_t lock; /* some global variable */ /* producer code */ /* consumer code */ while (true) { while (true) { /* do work */ acquire(lock); acquire(lock); if (counter == 0) { counter++; release(lock); release(lock); continue; } } /* do work */ counter--; release(lock); } "4 Mutex Implementation • Often involves a boolean variable indicating if lock is available or not! • release() is simply setting availability to true! • Busy waiting: during acquire(), keep looping until lock is freed! • Also known as a spinlock void release(mutex_t lock) { void acquire(mutex_t lock) { lock.available = true; while (!lock.available) } ; /* busy wait */ lock.available = false; } "5 Mutex Implementation • Busy waiting on a single-processor system is ine$cient (why?)! void release(mutex_t lock) { void acquire(mutex_t lock) { reenable preemption disable preemption } } • Mutex can be implemented by enabling and disabling preemption ! • Disabling preemption on a multi-processor system is ine$cient (why?) "6 Pthread Mutex Creation • In Pthread, a mutex is of type pthread_mutex_t! int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr); • First parameter is address to store the mutex identifier! • Second parameter gives options for mutex, or set to NULL for default settings! • Return value is always 0! • On Ubuntu, man pages for pthread_mutex_init() is in the glibc-doc package (sudo apt-get install glibc-doc) "7 Using Pthread Mutexes int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex); • Call pthread_mutex_lock() to acquire a mutex! • Call pthread_mutex_unlock() to release the mutex! • Call pthread_mutex_destroy() to free memory associated with mutex! • For all three of these functions, the parameter is a pointer to the mutex created by pthread_mutex_init()! • Return value is 0 on success, negative on error "8 Pthread Mutex Example Code /* initialization code */ pthread_mutex_t lock; pthread_mutex_init(&lock, NULL); /* producer thread */ /* consumer thread */ while (true) { while (true) { /* do work */ pthread_mutex_lock(&lock); pthread_mutex_lock(&lock); if (counter == 0) { counter++; pthread_mutex_unlock(&lock); pthread_mutex_unlock(&lock); continue; } } /* do work */ counter--; pthread_mutex_unlock(lock); } /* cleanup code */ pthread_mutex_destroy(&lock); "9 Semaphores • Whereas mutexes are boolean, semaphores are used to count accesses! • When creating a semaphore, initialize it to some value (often 0 or 1)! • wait() (originally called P()) - if value is 0, block; otherwise decrement by 1 and continue! • Also known as down() or take()! • signal() (originally called V()) - increment value by 1! • Also known as raise(), post(), up(), or give() "10 Semaphore Implementation void signal(semaphore_t sem) { void wait(semaphore_t sem) { sem++; while (sem <= 0) } ; /* busy wait */ sem--; } • Must guarantee that no two processes are executing signal() / wait() on same semaphore simultaneously! • Critical section is now the semaphore implementation! • On many operating systems, semaphores are implemented partially in userspace, and thus faster than mutexes "11 Semaphore Subtypes • Counting semaphore - value ranges from 0 to infinity! • Binary semaphore - value can only be 0 or 1 • If value is currently 0, signal() will increment it to 1! • If value is currently 1, signal() is a no-op "12 Semaphore Pseudocode semaphore_t sem; /* some global variable */ sem = 0; /* initialize semaphore to 0 */ /* producer code */ /* consumer code */ while (true) { while (true) { /* do work */ wait(sem); signal(sem); /* do work */ } } "13 Pthread Semaphore Creation • In Pthread, two types of semaphores (no binary semaphores):! • Unnamed semaphore: synchronizes threads and/or child processes! int sem_init(sem_t *sem, int pshared, int value); • First parameter is address to store semaphore identifier! • If second parameter is 1, semaphore will be shared with child processes created by fork()! • Third parameter is initial value for semaphore (often 0 or 1)! • Named semaphore: synchronizes threads and/or unrelated processes "14 Using Pthread Semaphores int sem_wait(sem_t *sem); int sem_post(sem_t *sem); int sem_destroy(sem_t *sem); • Call sem_wait() to decrement semaphore, blocking if already 0! • Call sem_post() to increment semaphore! • Call sem_destroy() to free memory associated with an unnamed semaphore! • For all three of these functions, the parameter is a pointer to the semaphore created by sem_init()! • Return value is 0 on success, negative on error "15 Pthread Semaphore Example Code /* initialization code */ sem_t sem; sem_init(&sem, 0, 0); /* producer thread */ /* consumer thread */ while (true) { while (true) { /* do work */ sem_wait(&sem) sem_post(&sem); /* do work */ } } /* cleanup code */ sem_destroy(&sem); "16 Deadlock • Deadlock: two or more processes waiting indefinitely for each other! • Example 1: let S and Q be two semaphores initialized to 1! Thread A Thread B wait(S); wait(Q); wait(Q); wait(S); … … signal(S); signal(Q); signal(Q); signal(S); • Example 2: let S and Q be initialized to 0 Thread A Thread B wait(S); wait(Q); … … signal(Q); signal(S); "17 Starvation • Starvation: indefinite blocking; some thread is always waiting! Thread A while (true) { /* do work */ signal(sem); } Thread B Thread C while (true) { while (true) { wait(sem); wait(sem); /* do work */ /* do different work */ } } • If both threads B and C are waiting, and if OS always picks the thread B to get the semaphore, then C will never execute "18 Priority Inversion • Scheduling problem when a lower-priority process holds a lock needed by higher-priority process! Thread A (high priority) Thread B (low priority) Thread C (medium priority) wait(sem); /* do work */ /* do work */ post(sem); • Thread B unable to post semaphore because OS keeps scheduling thread C! • Can be solved via priority-inheritance protocol! • When a process accesses resources needed by a higher-priority process, it inherits the higher priority, until it has finished with those resources "19 Avoiding Deadlocks • When acquiring multiple resources, release them in reverse order (like a stack)! • Use same acquisition order for all processes Thread A Thread B wait(S); wait(S); wait(Q); wait(Q); … … signal(Q); signal(Q); signal(S); signal(S); "20 Dining Philosophers Problem • Five philosophers sitting around a table, alternating thinking and eating! • No interaction with neighbors; occasionally try to pick 2 chopsticks (one at a time) to eat from bowl! • Need both to eat, then release both when done "21 Dining Philosophers Pseudocode • Declare array of 5 semaphores chopstick[5], all initialized to 1! • Each philosopher i thread runs this code:! while (true) { wait(chopstick[i]); wait(chopstick[(i + 1) % 5]); /* eat */ signal(chopstick[(i + 1) % 5]); signal(chopstick[i]); /* think */ } • What is the problem with this algorithm? "22 Resolving Dining Philosophers Algorithm • Allow at most 4 philosophers at table! • Allow a philosopher to pick up chopsticks only if both are available! • Put “pick up chopsticks” in a critical section! • Use asymmetric solution: odd-numbered philosopher pickup up left and then right chopstick, while even-numbered philosopher picks right and then left "23.

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    23 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us