operating systems · condition variables 2 • wait (cond_t *cv, mutex_t *lock) • assumes lock is...

212
Operating Systems Common Concurrency Problems Nipun Batra

Upload: others

Post on 04-Nov-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Operating Systems Common Concurrency Problems

Nipun Batra

Page 2: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables

2

• wait (cond_t *cv, mutex_t *lock)• Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock • When awoken, reacquires lock before returning

• signal (cond_t *cv)• Wake a single waiting thread • If there is no waiting thread, just return, do nothing

Page 3: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Page 4: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Page 5: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Page 6: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Page 7: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

Page 8: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

Page 9: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

When does wait return?

Page 10: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

When does wait return?When lock has been acquired.

Page 11: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

When does wait return?When lock has been acquired. What if some other thread holds the lock — block!

Page 12: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Condition Variables wait Pseudocode

3

• wait (cond_t *cv, mutex_t *lock)• Assume lock is held initially • pthread_mutex_unlock(lock) • block_on_condition(cv) • Move from Ready to Waiting/Blocked State • Move to Ready State • pthread_mutex_lock(lock)

Which of these are atomic?

Atomic

Signal

Why do we need to lock again?

When does wait return?When lock has been acquired. What if some other thread holds the lock — block!

Page 13: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Exercise: order using condition variables Correct Solution

4

1   void *child(void *arg) { 2       printf("child\n"); 3       thread_exit() 4       return NULL; }

7   int main(int argc, char *argv[]) { 8       printf("parent: begin\n"); 9       pthread_t c; 10       Pthread_create(&c, NULL, child, NULL); // create child 11       thread_join() 12       printf("parent: end\n"); 13       return 0; }

Page 14: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Exercise: order using condition variables Correct Solution

4

1   void *child(void *arg) { 2       printf("child\n"); 3       thread_exit() 4       return NULL; }

7   int main(int argc, char *argv[]) { 8       printf("parent: begin\n"); 9       pthread_t c; 10       Pthread_create(&c, NULL, child, NULL); // create child 11       thread_join() 12       printf("parent: end\n"); 13       return 0; }

void thread_exit { mutex_lock(&m)

Done = 1 cond_signal(&c) mutex_unlock(&m)

Page 15: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Exercise: order using condition variables Correct Solution

4

1   void *child(void *arg) { 2       printf("child\n"); 3       thread_exit() 4       return NULL; }

7   int main(int argc, char *argv[]) { 8       printf("parent: begin\n"); 9       pthread_t c; 10       Pthread_create(&c, NULL, child, NULL); // create child 11       thread_join() 12       printf("parent: end\n"); 13       return 0; }

void thread_exit { mutex_lock(&m)

Done = 1 cond_signal(&c) mutex_unlock(&m)

void thread_join { mutex_lock(&m) //w

while (done==0) //x cond_wait(&c, &m) //y mutex_unlock(&m) } //z

Page 16: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Exercise: Build a lock using semaphores

5

1  int sem_wait(sem_t *s) { 2    s->value -= 1 3     wait if s->value <0 4  }

Refresher Notes

1  int sem_post(sem_t *s) { 2     s->value += 1 3     wake one waiting thread if any 4  }

1   sem_t m; 2   sem_init(&m, 0, 1); 3 4   sem_wait(&m); 5   //critical section here 6   sem_post(&m);

Page 17: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Page 18: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

Page 19: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

Page 20: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

Page 21: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

Page 22: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

Page 23: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

Page 24: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

Page 25: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

Page 26: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

Page 27: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

Page 28: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

Page 29: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

Page 30: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Page 31: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

Page 32: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

Page 33: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

-1 wake(T1) Running Ready

Page 34: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

-1 wake(T1) Running Ready

-1 sem_post() returns Running Ready

Page 35: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

-1 wake(T1) Running Ready

-1 sem_post() returns Running Ready

-1 Interrupt; Switch → T1 Ready Running

Page 36: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

-1 wake(T1) Running Ready

-1 sem_post() returns Running Ready

-1 Interrupt; Switch → T1 Ready Running

Page 37: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

6

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call sem_wait() Running Ready Ready

0 sem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call sem_wait() Running Ready

-1 Ready decrement sem Running Ready

-1 Ready (sem < 0)→sleep sleeping Ready

-1 Running Switch → T2 sleeping Running

-1 Call sem_wait() Running

-2 (crit sect: end) Running sleeping Decrement sem Running

-2 call sem_post() Running sleeping (sem<0) -> Sleep Sleeping

Switch T1

-1 Increment sem

-1 wake(T1) Running Ready

-1 sem_post() returns Running Ready

-1 Interrupt; Switch → T1 Ready Running

Can T1 run before sem_post returns?

NO!

Page 38: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

Page 39: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

• Build semaphores using locks and condition variables

Page 40: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

• Build semaphores using locks and condition variables• Any critical section should require locking

Page 41: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition

Page 42: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 43: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 44: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

API

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 45: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

API Our implementation

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 46: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

1 #include <semaphore.h> 2 sem_t s;

API Our implementation

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 47: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

7

1 typedef struct __Zem_t { 2   int value; 3   pthread_cond_t cond; 4   pthread_mutex_t lock; 5 } Zem_t; 6

1 #include <semaphore.h> 2 sem_t s;

API Our implementation

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition• Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 48: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 49: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 50: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

API

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 51: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

API Our implementation

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 52: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

API Our implementation

1  int sem_init(sem_t *s, int init_val) { 2    s->value=init_val; 3    }

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 53: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

8

API Our implementation

1  int sem_init(sem_t *s, int init_val) { 2    s->value=init_val; 3    }

1 // only one thread can call this 2 void Zem_init(Zem_t *s, int value) { 3   s->value = value; 4   Cond_init(&s->cond); 5   Mutex_init(&s->lock); 6 }

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 54: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 55: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 56: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API

Page 57: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

Page 58: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

1  int sem_post(sem_t *s) { 2     s->value += 1 3     wake one waiting thread if any 4  }

Page 59: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

Atomic operation

1  int sem_post(sem_t *s) { 2     s->value += 1 3     wake one waiting thread if any 4  }

Page 60: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

9

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

Atomic operation

1  int sem_post(sem_t *s) { 2     s->value += 1 3     wake one waiting thread if any 4  }

void Zem_post(Zem_t *s) { 23   Mutex_lock(&s->lock); 24   s->value++; 25   Cond_signal(&s->cond); 26   Mutex_unlock(&s->lock); 27 }

Page 61: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 62: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

Page 63: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API

Page 64: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

Page 65: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

1  int sem_wait(sem_t *s) { 2    s->value -= 1 3     wait if s->value <0 4  }

Page 66: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

1  int sem_wait(sem_t *s) { 2    s->value -= 1 3     wait if s->value <0 4  }

Atomic operation

Page 67: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

1  int sem_wait(sem_t *s) { 2    s->value -= 1 3     wait if s->value <0 4  }

Atomic operation

void Zem_wait(Zem_t *s) {

1 Mutex_lock(&s->lock);

2   while (s->value <= 0) 3   Cond_wait(&s->cond, &s->lock); 4   s->value--; 5   Mutex_unlock(&s->lock); 6 }

Page 68: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Semaphores Implementation

10

• Build semaphores using locks and condition variables• Any critical section should require locking • Signal and Wait on condition • Don’t maintain the invariant that the value of the semaphore, when

negative, reflects the number of waiting threads

API Our implementation

1  int sem_wait(sem_t *s) { 2    s->value -= 1 3     wait if s->value <0 4  }

Atomic operation

void Zem_wait(Zem_t *s) {

1 Mutex_lock(&s->lock);

2   while (s->value <= 0) 3   Cond_wait(&s->cond, &s->lock); 4   s->value--; 5   Mutex_unlock(&s->lock); 6 }

Should it be ==0?

Page 69: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Page 70: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

Page 71: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

Page 72: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

Page 73: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

Page 74: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

Page 75: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

Page 76: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

Page 77: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

Page 78: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

Page 79: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

Page 80: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

Page 81: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

Page 82: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Page 83: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

Page 84: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

1 Increments zem Running

Page 85: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

1 Increments zem Running

1 Wakes up thread T1 Running Ready

Page 86: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

1 Increments zem Running

1 Wakes up thread T1 Running ReadyCondition wait will return once it

gets lock Ready

Page 87: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

1 Increments zem Running

1 Wakes up thread T1 Running ReadyCondition wait will return once it

gets lock Ready

1 zem_post() returns Running Ready

Page 88: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

11

Value Thread  0 State Thread  1 State T2 State

1 Running Ready Ready

1 call zem_wait() Running Ready Ready

0 zem_wait() retruns Running Ready Ready

0 (crit set: begin) Running Ready Ready

0 Interrupt; Switch → T1 Ready Running Ready

0 Ready call zem_wait() Running Ready

0 Ready (zem <= 0)→sleep sleeping Ready

0 Running Switch → T2 sleeping Running

0 Call zem_wait() Running

0 (zem<0) -> Sleep Sleeping

0 (crit sect: end) Running sleeping Switch —> T1 Sleeping

0 call sem_post() Running sleeping

Acquires lock Running

1 Increments zem Running

1 Wakes up thread T1 Running ReadyCondition wait will return once it

gets lock Ready

1 zem_post() returns Running Ready

0 Zem = zem - 1 Running

Page 89: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Another Implementation …

12

Page 90: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs

13Types of bugs in 4 major projects from 500K bug reports

Page 91: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

Page 92: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

MySQL bug …

Page 93: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

1     Thread1:: 2     if(thd->proc_info){ 3       … 4   fputs(thd->proc_info , …); 5   … 6     }

MySQL bug …

Page 94: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

1     Thread1:: 2     if(thd->proc_info){ 3       … 4   fputs(thd->proc_info , …); 5   … 6     }

8     Thread2::9     thd->proc_info = NULL;

MySQL bug …

Page 95: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

1     Thread1:: 2     if(thd->proc_info){ 3       … 4   fputs(thd->proc_info , …); 5   … 6     }

8     Thread2::9     thd->proc_info = NULL;

• Is this problematic?

MySQL bug …

Page 96: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

1     Thread1:: 2     if(thd->proc_info){ 3       … 4   fputs(thd->proc_info , …); 5   … 6     }

8     Thread2::9     thd->proc_info = NULL;

• Is this problematic?• Yes, else we wouldn’t be discussing …

MySQL bug …

Page 97: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

14

1     Thread1:: 2     if(thd->proc_info){ 3       … 4   fputs(thd->proc_info , …); 5   … 6     }

8     Thread2::9     thd->proc_info = NULL;

• Is this problematic?• Yes, else we wouldn’t be discussing …• How?

MySQL bug …

Page 98: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

15

1 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 2 3 Thread1:: 4 pthread_mutex_lock(&lock); 5 if(thd->proc_info){ 6   … 7   fputs(thd->proc_info , …); 8   … 9 } 10 pthread_mutex_unlock(&lock);

1 Thread2:: 2 pthread_mutex_lock(&lock); 3 thd->proc_info = NULL; 4 pthread_mutex_unlock(&lock);

Page 99: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Atomicity

15

1 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 2 3 Thread1:: 4 pthread_mutex_lock(&lock); 5 if(thd->proc_info){ 6   … 7   fputs(thd->proc_info , …); 8   … 9 } 10 pthread_mutex_unlock(&lock);

1 Thread2:: 2 pthread_mutex_lock(&lock); 3 thd->proc_info = NULL; 4 pthread_mutex_unlock(&lock);

Simple Solution

Page 100: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

16

1 Thread1:: 2 void init(){ 3   mThread = PR_CreateThread(mMain, …); 4 } 5

6 Thread2:: 7 void mMain(…){ 8   mState = mThread->State 9 }

Page 101: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

16

1 Thread1:: 2 void init(){ 3   mThread = PR_CreateThread(mMain, …); 4 } 5

6 Thread2:: 7 void mMain(…){ 8   mState = mThread->State 9 }

Mozilla bug …

Page 102: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

16

1 Thread1:: 2 void init(){ 3   mThread = PR_CreateThread(mMain, …); 4 } 5

6 Thread2:: 7 void mMain(…){ 8   mState = mThread->State 9 }

Mozilla bug …

• Is this problematic?

Page 103: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

16

1 Thread1:: 2 void init(){ 3   mThread = PR_CreateThread(mMain, …); 4 } 5

6 Thread2:: 7 void mMain(…){ 8   mState = mThread->State 9 }

Mozilla bug …

• Is this problematic?• Yes, else we wouldn’t be discussing …

Page 104: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

16

1 Thread1:: 2 void init(){ 3   mThread = PR_CreateThread(mMain, …); 4 } 5

6 Thread2:: 7 void mMain(…){ 8   mState = mThread->State 9 }

Mozilla bug …

• Is this problematic?• Yes, else we wouldn’t be discussing …• How?

Page 105: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

17

Page 106: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

17

1 pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER; 2 pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER; 3 int mtInit = 0;

Page 107: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

17

1 Thread 1:: 2 void init(){ 3   … 4   mThread = PR_CreateThread(mMain,…); 5 6   // signal that the thread has been created. 7   pthread_mutex_lock(&mtLock); 8   mtInit = 1; 9   pthread_cond_signal(&mtCond); 10   pthread_mutex_unlock(&mtLock); 11   … 12 }

1 pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER; 2 pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER; 3 int mtInit = 0;

Page 108: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Order Violation

17

1 Thread 1:: 2 void init(){ 3   … 4   mThread = PR_CreateThread(mMain,…); 5 6   // signal that the thread has been created. 7   pthread_mutex_lock(&mtLock); 8   mtInit = 1; 9   pthread_cond_signal(&mtCond); 10   pthread_mutex_unlock(&mtLock); 11   … 12 }

1 pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER; 2 pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER; 3 int mtInit = 0;

20 Thread2:: 21 void mMain(…){

// wait for the thread to be initialized … 22   pthread_mutex_lock(&mtLock); 23   while(mtInit == 0) 24   pthread_cond_wait(&mtCond, &mtLock); 25   pthread_mutex_unlock(&mtLock); 26   mState = mThread->State; }

Page 109: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Page 110: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Page 111: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Page 112: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1

Page 113: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Thread T1 gets Lock L2

Page 114: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Thread T1 gets Lock L2• Thread T1 completes critical section

Page 115: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Thread T1 gets Lock L2• Thread T1 completes critical section• Context Switch

Page 116: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Thread T1 gets Lock L2• Thread T1 completes critical section• Context Switch• Thread T2 gets Lock L2 and Lock L1

Page 117: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

18

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Thread T1 gets Lock L2• Thread T1 completes critical section• Context Switch• Thread T2 gets Lock L2 and Lock L1• Works :)

Page 118: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Page 119: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Page 120: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Page 121: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1

Page 122: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch

Page 123: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2

Page 124: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2• Context Switch

Page 125: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2• Context Switch• Thread T1 waits since it doesn’t have Lock 2

Page 126: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2• Context Switch• Thread T1 waits since it doesn’t have Lock 2• Context Switch

Page 127: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2• Context Switch• Thread T1 waits since it doesn’t have Lock 2• Context Switch• Thread t2 waits since it doesn’t have Lock 1

Page 128: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock

19

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

• Thread T1 gets Lock L1• Context Switch• Thread T2 gets Lock L2• Context Switch• Thread T1 waits since it doesn’t have Lock 2• Context Switch• Thread t2 waits since it doesn’t have Lock 1

Page 129: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

20

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Lock 1Thread 1

Thread 2Lock 2

Holds

Holds

Wan

ted

by

Wan

ted

by

Page 130: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

Page 131: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation

Page 132: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

Page 133: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]

Page 134: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]

Page 135: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]

Page 136: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]• If addAll is multithreaded & assuming it locks V1,

V2 in that order

Page 137: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]• If addAll is multithreaded & assuming it locks V1,

V2 in that order• If some thread all calls V2.add(V1), we have a

deadlock!

Page 138: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]• If addAll is multithreaded & assuming it locks V1,

V2 in that order• If some thread all calls V2.add(V1), we have a

deadlock!• Complex dependecies

Page 139: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]• If addAll is multithreaded & assuming it locks V1,

V2 in that order• If some thread all calls V2.add(V1), we have a

deadlock!• Complex dependecies

• Virtual memory system calls filesystem

Page 140: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Why Deadlocks Occur

21

• Encapsulation• Example: Java vector addAll method

• V1 = [1, 4, 5]• V2 = [6, 7, 8]• V1.addAll(V2) —> [1, 4, 5, 6, 7, 8]• If addAll is multithreaded & assuming it locks V1,

V2 in that order• If some thread all calls V2.add(V1), we have a

deadlock!• Complex dependecies

• Virtual memory system calls filesystem• Filesystem calls virtual memory

Page 141: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Page 142: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Condition Description

Page 143: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Page 144: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

Page 145: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Page 146: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

22

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Circular waitThere exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain

Page 147: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Page 148: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Condition Description

Page 149: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Page 150: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

Page 151: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Page 152: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

23

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Circular wait

There exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain

Page 153: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

24

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 154: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

24

• Provide a total ordering of lock acquisition

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 155: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

24

• Provide a total ordering of lock acquisition

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 156: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

24

• Provide a total ordering of lock acquisition

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L1); Lock(L2);

Non-deadlock Version

Page 157: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

Page 158: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition

Page 159: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition

Page 160: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition• Define a function do_something which works correct

even if two threads call it as:

Page 161: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition• Define a function do_something which works correct

even if two threads call it as:• T1 — do_something (L1, L2) and

Page 162: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition• Define a function do_something which works correct

even if two threads call it as:• T1 — do_something (L1, L2) and• T2 — do_something (L2, L1)

Page 163: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition

do something(mutex t *m1, mutex t *m2)

• Define a function do_something which works correct even if two threads call it as:• T1 — do_something (L1, L2) and• T2 — do_something (L2, L1)

Page 164: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Circular Wait

25

• Provide a total ordering of lock acquisition

do something(mutex t *m1, mutex t *m2)

• Define a function do_something which works correct even if two threads call it as:• T1 — do_something (L1, L2) and• T2 — do_something (L2, L1)

if (m1 > m2) { // grab locks in high-to-low address order pthread_mutex_lock(m1); pthread_mutex_lock(m2); } else { pthread_mutex_lock(m2); pthread_mutex_lock(m1); } // Code assumes that m1 != m2 (it is not the same lock)

Page 165: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Page 166: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Condition Description

Page 167: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Page 168: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

Page 169: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Page 170: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

26

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Circular waitThere exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain

Page 171: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

27

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 172: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

27

• Acquire all locks at once atomically

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 173: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

27

• Acquire all locks at once atomically

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Page 174: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

27

• Acquire all locks at once atomically

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Thread 1 Lock(ALL) Lock(L1); Lock(L2); ….. Unlock(ALL);

Thread 2 Lock(ALL) Lock(L1); Lock(L2); … Unlock(ALL)

Non-deadlock Version

Page 175: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

28

• Acquire all locks at once atomically

Thread 1 Lock(ALL) Lock(L1); Lock(L2); ….. Unlock(ALL);

Thread 2 Lock(ALL) Lock(L1); Lock(L2); … Unlock(ALL)

Non-deadlock Version

Page 176: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

28

• Acquire all locks at once atomically

Thread 1 Lock(ALL) Lock(L1); Lock(L2); ….. Unlock(ALL);

Thread 2 Lock(ALL) Lock(L1); Lock(L2); … Unlock(ALL)

Non-deadlock Version

• Cons

Page 177: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

28

• Acquire all locks at once atomically

Thread 1 Lock(ALL) Lock(L1); Lock(L2); ….. Unlock(ALL);

Thread 2 Lock(ALL) Lock(L1); Lock(L2); … Unlock(ALL)

Non-deadlock Version

• Cons• Requires us to know which all locks will be required

ahead of time

Page 178: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Preventing Hold and Wait

28

• Acquire all locks at once atomically

Thread 1 Lock(ALL) Lock(L1); Lock(L2); ….. Unlock(ALL);

Thread 2 Lock(ALL) Lock(L1); Lock(L2); … Unlock(ALL)

Non-deadlock Version

• Cons• Requires us to know which all locks will be required

ahead of time• Reduction of concurrency

Page 179: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Page 180: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Condition Description

Page 181: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Page 182: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

Page 183: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Page 184: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

29

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Circular waitThere exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain

Page 185: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Pre-emption

30

1 top: 2   lock(L1); 3   if( tryLock(L2) == -1 ){ 4   unlock(L1);  5   goto top; 6   }

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Non-deadlock Version

Page 186: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Pre-emption

31

1 top: 2   lock(L1); 3   if( tryLock(L2) == -1 ){ 4   unlock(L1);  5   goto top; 6   }

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Non-deadlock Version

Page 187: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Pre-emption

31

• Livelock: Both threads running this sequence repeatedly

1 top: 2   lock(L1); 3   if( tryLock(L2) == -1 ){ 4   unlock(L1);  5   goto top; 6   }

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Non-deadlock Version

Page 188: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Pre-emption

31

• Livelock: Both threads running this sequence repeatedly• How to solve?

1 top: 2   lock(L1); 3   if( tryLock(L2) == -1 ){ 4   unlock(L1);  5   goto top; 6   }

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Non-deadlock Version

Page 189: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Pre-emption

31

• Livelock: Both threads running this sequence repeatedly• How to solve?

• Add random delay

1 top: 2   lock(L1); 3   if( tryLock(L2) == -1 ){ 4   unlock(L1);  5   goto top; 6   }

Thread 1 Lock(L1); Lock(L2);

Thread 2 Lock(L2); Lock(L1);

Deadlock Version

Non-deadlock Version

Page 190: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Concurrency Bugs — Deadlock Dependency Graphs

32

Condition Description

Mutual Exclusion

Threads claim exclusive control of resources that they require.

Hold-and-wait

Threads hold resources allocated to them while waiting for additional resources

No preemption

Resources cannot be forcibly removed from threads that are holding them.

Circular waitThere exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain

Page 191: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

33

Page 192: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

33

• Use atomic instructions!

Page 193: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

33

• Use atomic instructions!

1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

Page 194: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

33

• Use atomic instructions!

1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

• Use above code to implement atomic increment: x = x+k

Page 195: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

33

• Use atomic instructions!

1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

1 void AtomicIncrement(int *value, int amount){ …Fill Here 5 }

• Use above code to implement atomic increment: x = x+k

Page 196: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

34

• Use atomic instructions!

1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

1 void AtomicIncrement(int *value, int amount){ 2 do{ 3   int old = *value; 4   }while( CompareAndSwap(value, old, old+amount)==0); 5 }

• Use above code to implement atomic increment: x = x+k

Page 197: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

35

• List insertion using atomic instructions

Page 198: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

35

• List insertion using atomic instructions

1 void insert(int value){ 2   node_t * n = malloc(sizeof(node_t)); 3   assert( n != NULL ); 4   n->value  = value ; 5   n->next   = head; 6   head   = n; 7 }

Page 199: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

35

• List insertion using atomic instructions

1 void insert(int value){ 2   node_t * n = malloc(sizeof(node_t)); 3   assert( n != NULL ); 4   n->value  = value ; 5   n->next   = head; 6   head   = n; 7 }

• Where is the race condition?

Page 200: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

36

• Mutex based solution

Page 201: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

36

• Mutex based solution

1 void insert(int value){ 2   node_t * n = malloc(sizeof(node_t)); 3   assert( n != NULL ); 4   n->value = value ; 5   lock(listlock); // begin critical section 6   n->next  = head; 7   head   = n; 8   unlock(listlock) ;  //end critical section 9 }

Page 202: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

37

• Atomic instruction based?HINT 1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

Page 203: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Prevention — Mutual exclusion

37

• Atomic instruction based?

1 void insert(int value) { 2   node_t *n = malloc(sizeof(node_t)); 3   assert(n != NULL); 4   n->value = value; 5   do { 6   n->next = head; 7   } while (CompareAndSwap(&head, n->next, n)); 8 }

HINT 1 int CompareAndSwap(int *address, int expected, int new){ 2   if(*address == expected){ 3   *address = new; 4   return 1; // success 5   } 6   return 0; 7 }

Page 204: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

Only one of T1 & T2 will run at a given time …

Page 205: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

• Global knowledge about which threads might be acquired is needed ahead of time

Only one of T1 & T2 will run at a given time …

Page 206: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

• Global knowledge about which threads might be acquired is needed ahead of time

• Assume 2 processors and 4 threads and following lock requirements. How will you schedule to avoid deadlocks?

Only one of T1 & T2 will run at a given time …

Page 207: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

• Global knowledge about which threads might be acquired is needed ahead of time

• Assume 2 processors and 4 threads and following lock requirements. How will you schedule to avoid deadlocks?• Hint: you can think serial!

Only one of T1 & T2 will run at a given time …

Page 208: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

• Global knowledge about which threads might be acquired is needed ahead of time

• Assume 2 processors and 4 threads and following lock requirements. How will you schedule to avoid deadlocks?• Hint: you can think serial!

T1 T2 T3 T4L1 yes yes no noL2 yes yes yes no

Only one of T1 & T2 will run at a given time …

Page 209: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

38

• Global knowledge about which threads might be acquired is needed ahead of time

• Assume 2 processors and 4 threads and following lock requirements. How will you schedule to avoid deadlocks?• Hint: you can think serial!

T1 T2 T3 T4L1 yes yes no noL2 yes yes yes no

T1 T2

T3 T4

CPU1CPU2 Only one of T1 & T2 will

run at a given time …

Page 210: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

39

Page 211: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

39

T1 T2 T3 T4

L1 yes yes yes no

L2 yes yes yes no

Page 212: Operating Systems · Condition Variables 2 • wait (cond_t *cv, mutex_t *lock) • Assumes lock is held when wait() is called • Puts caller to sleep + atomically releases lock

Deadlock Avoidance via Scheduling

39

T1 T2 T3 T4

L1 yes yes yes no

L2 yes yes yes no

T1 T2 T3

T4

CPU1CPU2