Synchronization and Semaphores Copyright University of Illinois CS

  • Slides: 44
Download presentation
Synchronization and Semaphores Copyright ©: University of Illinois CS 241 Staff 1

Synchronization and Semaphores Copyright ©: University of Illinois CS 241 Staff 1

Discussion n In uni-processors ¡ ¡ ¡ Concurrent processes cannot be overlapped, only interleaved

Discussion n In uni-processors ¡ ¡ ¡ Concurrent processes cannot be overlapped, only interleaved A process runs until it invokes a system call, or is interrupted To guarantee mutual exclusion, hardware support could help by allowing the disabling of interrupts While(true) { /* disable interrupts */ /* critical section */ /* enable interrupts */ /* remainder */ } ¡ What’s the problem with this solution? Copyright ©: University of Illinois CS 241 Staff 2

Discussion n In multi-processors ¡ ¡ ¡ Several processors share memory Processors behave independently

Discussion n In multi-processors ¡ ¡ ¡ Several processors share memory Processors behave independently in a peer relationship Interrupt disabling will not work We need hardware support where access to a memory location excludes any other access to that same location The hardware support is based on execution of multiple instructions atomically (test and set) Copyright ©: University of Illinois CS 241 Staff 3

Test and Set Instruction boolean Test_And_Set(boolean* lock) atomic { boolean initial; initial = *lock;

Test and Set Instruction boolean Test_And_Set(boolean* lock) atomic { boolean initial; initial = *lock; *lock = true; return initial; } atomic = executed in a single shot without any interruption Note: this is more accurate than the textbook version Copyright ©: University of Illinois CS 241 Staff 4

Using Test_And_Set for Mutual Exclusion Pi { while(1) { while(Test_And_Set(lock)) { /* spin */

Using Test_And_Set for Mutual Exclusion Pi { while(1) { while(Test_And_Set(lock)) { /* spin */ } void main () { lock = 0; parbegin(P 1, …, Pn); } /* Critical Section */ lock =0; /* remainder */ } } What's the problem? Copyright ©: University of Illinois CS 241 Staff 5

Using Test_And_Set for Mutual Exclusion Pi { while(1) { while(Test_And_Set(lock)) { /* spin */

Using Test_And_Set for Mutual Exclusion Pi { while(1) { while(Test_And_Set(lock)) { /* spin */ } void main () { lock = 0; parbegin(P 1, …, Pn); } /* Critical Section */ lock =0; /* remainder */ } } Works, but has performance loss because of busy waiting. Copyright ©: University of Illinois CS 241 Staff 6

Semaphores n Fundamental Principle: ¡ n Two or more processes want to cooperate by

Semaphores n Fundamental Principle: ¡ n Two or more processes want to cooperate by means of simple signals Special Variable: semaphore s ¡ ¡ A special kind of “int” variable Can’t just modify or set or increment or decrement it Copyright ©: University of Illinois CS 241 Staff 7

Semaphores n Before entering critical section ¡ sem. Wait(s) n Receive signal via semaphore

Semaphores n Before entering critical section ¡ sem. Wait(s) n Receive signal via semaphore s n “down” on the semaphore Also: P – proberen n n After finishing critical section ¡ sem. Signal(s) n Transmit signal via semaphore s n “up” on the semaphore Also: V – verhogen n n Implementation requirements ¡ sem. Signal and sem. Wait must be atomic Copyright ©: University of Illinois CS 241 Staff 8

Semaphores vs. Test_and_Set Semaphore Test_and_Set semaphore s = 1; Pi { while(1) { sem.

Semaphores vs. Test_and_Set Semaphore Test_and_Set semaphore s = 1; Pi { while(1) { sem. Wait(s); /* Critical Section */ sem. Signal(s); /* remainder */ } } lock = 0; Pi { while(1) { while(Test_And_Set(lock)); /* Critical Section */ lock =0; /* remainder */ } } n Avoid busy waiting by suspending ¡ ¡ Block if s == False Wakeup on signal (s = True) Copyright ©: University of Illinois CS 241 Staff 9

Inside a Semaphore n Requirement ¡ n No two processes can execute wait() and

Inside a Semaphore n Requirement ¡ n No two processes can execute wait() and signal() on the same semaphore at the same time! Critical section ¡ wait() and signal() code ¡ Now have busy waiting in critical section implementation Implementation code is short Little busy waiting if critical section rarely occupied Bad for applications may spend lots of time in critical sections Copyright ©: University of Illinois CS 241 Staff 10

Inside a Semaphore n n Add a waiting queue Multiple process waiting on s

Inside a Semaphore n n Add a waiting queue Multiple process waiting on s ¡ Wakeup one of the blocked processes upon getting a signal n Semaphore data structure typedef struct { int count; queue. Type queue; /* queue for procs. waiting on s */ } SEMAPHORE; Copyright ©: University of Illinois CS 241 Staff 11

Binary Semaphores typedef struct bsemaphore { enum {0, 1} value; queue. Type queue; }

Binary Semaphores typedef struct bsemaphore { enum {0, 1} value; queue. Type queue; } BSEMAPHORE; void sem. Wait. B(bsemaphore s) { if (s. value == 1) s. value = 0; else { place P in s. queue; block P; } } void sem. Signal. B (bsemaphore s) { if (s. queue is empty()) s. value = 1; else { remove P from s. queue; place P on ready list; } } Copyright ©: University of Illinois CS 241 Staff 12

General Semaphore typedef struct { int count; queue. Type queue; } SEMAPHORE; void sem.

General Semaphore typedef struct { int count; queue. Type queue; } SEMAPHORE; void sem. Wait(semaphore s) { s. count--; if (s. count < 0) { place P in s. queue; block P; } } void sem. Signal(semaphore s) { s. count++; if (s. count ≤ 0) { remove P from s. queue; place P on ready list; } } Copyright ©: University of Illinois CS 241 Staff 13

Making the operations atomic n n Isn’t this exactly what semaphores were trying to

Making the operations atomic n n Isn’t this exactly what semaphores were trying to solve? Are we stuck? ! Solution: resort to test-and-set typedef struct { boolean lock; int count; queue. Type queue; } SEMAPHORE; void sem. Wait(semaphore s) { void sem. Wait(semaphore while (test_and_set(lock)) { } s. count--; if (s. count < 0) { P in s. queue; place Pblock in s. queue; P; block } P; }} lock = 0; } Copyright ©: University of Illinois CS 241 Staff 14

Making the operations atomic n n Busy-waiting again! Then how are semaphores better than

Making the operations atomic n n Busy-waiting again! Then how are semaphores better than just using test_and_set? void sem. Wait(semaphore s) { while (test_and_set(lock)) { } s. count--; if (s. count < 0) { place P in s. queue; block P; } lock = 0; } n T&S: busy-wait during critical section n Sem. : busy-wait just during sem. Wait, sem. Signal: very short operations! Copyright ©: University of Illinois CS 241 Staff 15

Mutual Exclusion Using Semaphores semaphore s = 1; Pi { while(1) { sem. Wait(s);

Mutual Exclusion Using Semaphores semaphore s = 1; Pi { while(1) { sem. Wait(s); /* Critical Section */ sem. Signal(s); /* remainder */ } } Copyright ©: University of Illinois CS 241 Staff 16

Value of Semaphore lock Queue 1 0 B -1 Process A Process B sem.

Value of Semaphore lock Queue 1 0 B -1 Process A Process B sem. Wait(lock) Critical Region Normal Execution Blocked on semaphore lock sem. Wait(lock) sem. Signal(lock) 0 sem. Signal(lock) 1 Copyright ©: University of Illinois CS 241 Staff 17

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? n When might this be desirable? Copyright ©: University of Illinois CS 241 Staff 18

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? n When might this be desirable? ×× × -1 s = 2 1 0 Copyright ©: University of Illinois CS 241 Staff 19

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 1 semaphore s = 2; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? ¡ n Allows up to 2 processes to enter CS When might this be desirable? ¡ Need up to 2 processes inside CS n ¡ e. g. , limit number of processes reading a var Be careful not to violate mutual exclusion inside CS! Copyright ©: University of Illinois CS 241 Staff 20

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? n When might this be desirable? Copyright ©: University of Illinois CS 241 Staff 21

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? n When might this be desirable? × × -2 × -3 s = 0 -1 Copyright ©: University of Illinois CS 241 Staff 22

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /*

Semaphore Example 2 semaphore s = 0; Pi { while(1) { sem. Wait(s); /* CS */ sem. Signal(s); /* remainder */ } } n What happens? ¡ n No one can enter CS! Ever! When might this be desirable? ¡ Never! Copyright ©: University of Illinois CS 241 Staff 23

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1 { P 2 { /* do some stuff */ sem. Wait(s); sem. Signal(s); /* do some more stuff */ } } n What happens? n When might this be desirable? Copyright ©: University of Illinois CS 241 Staff 24

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1 { P 2 { /* do some stuff */ sem. Wait(s); sem. Signal(s); /* do some more stuff */ } } n What happens? ×× 1 s = 1 0 n When might this be desirable? Copyright ©: University of Illinois CS 241 Staff 25

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1

Semaphore Example 3 semaphore s = 0; semaphore s; /* shared */ P 1 { P 2 { /* do some stuff */ sem. Wait(s); sem. Signal(s); /* do some more stuff */ } } n What happens? ¡ ¡ n P 1 waits until P 2 signals if P 2 signals first, P 1 does not wait When might this be desirable? ¡ Having a process/thread wait for another process/thread Copyright ©: University of Illinois CS 241 Staff 26

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); }

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); } n n Process 2 executes: while(1) { sem. Wait(Q); b; sem. Signal(S); } Two processes n Two semaphores: S and Q n Protect two critical variables ‘a’ and ‘b’. What happens in the pseudocode if Semaphores S and Q are initialized to 1 (or 0)? Copyright ©: University of Illinois CS 241 Staff 27

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); }

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); } Process 2 executes: while(1) { sem. Wait(Q); b; sem. Signal(S); } × =× 0 -1 S = 0 -1 Q Copyright ©: University of Illinois CS 241 Staff 28

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); }

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); } Process 2 executes: while(1) { sem. Wait(Q); b; sem. Signal(S); } ×× × 0 =× 1 × 0 × 1 0 S = 1 0 1 Q Copyright ©: University of Illinois CS 241 Staff 29

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); }

Semaphore Example 4 Process 1 executes: while(1) { sem. Wait(S); a; sem. Signal(Q); } Process 2 executes: while(1) { sem. Wait(Q); b; sem. Signal(S); } ×× × × 1 =× 1 × 0 × 1 0 S = 1 0 -1 0 Q Copyright ©: University of Illinois CS 241 Staff 30

Be careful! Deadlock or Violation of Mutual Exclusion? 1 sem. Signal(s); critical_section(); sem. Wait(s);

Be careful! Deadlock or Violation of Mutual Exclusion? 1 sem. Signal(s); critical_section(); sem. Wait(s); 2 sem. Wait(s); critical_section(); 3 critical_section(); sem. Signal(s); 4 5 sem. Wait(s); critical_section(); sem. Signal(s); Copyright ©: University of Illinois CS 241 Staff 31

Be careful! Mutual exclusion violation 1 sem. Signal(s); critical_section(); sem. Wait(s); Certain deadlock! 4

Be careful! Mutual exclusion violation 1 sem. Signal(s); critical_section(); sem. Wait(s); Certain deadlock! 4 Deadlock again! Possible deadlock 2 sem. Wait(s); critical_section(); 5 Mutual exclusion violation 3 critical_section(); sem. Signal(s); sem. Wait(s); critical_section(); sem. Signal(s); Copyright ©: University of Illinois CS 241 Staff 32

POSIX Semaphores n Named Semaphores ¡ ¡ n Provides synchronization between unrelated process and

POSIX Semaphores n Named Semaphores ¡ ¡ n Provides synchronization between unrelated process and related process as well as between threads Kernel persistence System-wide and limited in number Uses sem_open Unnamed Semaphores ¡ ¡ ¡ Provides synchronization between threads and between related processes Thread-shared or process-shared Uses sem_init Copyright ©: University of Illinois CS 241 Staff 33

POSIX Semaphores n Data type ¡ Semaphore is a variable of type sem_t n

POSIX Semaphores n Data type ¡ Semaphore is a variable of type sem_t n Include <semaphore. h> n Atomic Operations int sem_init(sem_t *sem, int pshared, unsigned value); int sem_destroy(sem_t *sem); int sem_post(sem_t *sem); int sem_trywait(sem_t *sem); int sem_wait(sem_t *sem); Copyright ©: University of Illinois CS 241 Staff 34

Unnamed Semaphores #include <semaphore. h> int sem_init(sem_t *sem, int pshared, unsigned value); n Initialize

Unnamed Semaphores #include <semaphore. h> int sem_init(sem_t *sem, int pshared, unsigned value); n Initialize an unnamed semaphore n Returns You cannot make a copy of a ¡ ¡ n 0 on success -1 on failure, sets errno semaphore variable!!! Parameters ¡ sem: n ¡ pshared: n n ¡ Target semaphore 0: only threads of the creating process can use the semaphore Non-0: other processes can use the semaphore value: n Initial value of the semaphore Copyright ©: University of Illinois CS 241 Staff 35

Sharing Semaphores n Sharing semaphores between threads within a process is easy, use pshared==0

Sharing Semaphores n Sharing semaphores between threads within a process is easy, use pshared==0 ¡ n Forking a process creates copies of any semaphore it has… sem_t semaphores are not shared across processes A non-zero pshared allows any process that can access the semaphore to use it ¡ Places the semaphore in the global (OS) environment Copyright ©: University of Illinois CS 241 Staff 36

sem_init can fail n On failure ¡ sem_init returns -1 and sets errno EINVAL

sem_init can fail n On failure ¡ sem_init returns -1 and sets errno EINVAL ENOSPC EPERM cause Value > sem_value_max Resources exhausted Insufficient privileges sem_t sem. A; if (sem_init(&sem. A, 0, 1) == -1) perror(“Failed to initialize semaphore sem. A”); Copyright ©: University of Illinois CS 241 Staff 37

Semaphore Operations #include <semaphore. h> int sem_destroy(sem_t *sem); n Destroy an semaphore n Returns

Semaphore Operations #include <semaphore. h> int sem_destroy(sem_t *sem); n Destroy an semaphore n Returns ¡ ¡ n 0 on success -1 on failure, sets errno Parameters ¡ sem: n n Target semaphore Notes ¡ ¡ ¡ Can destroy a sem_t only once Destroying a destroyed semaphore gives undefined results Destroying a semaphore on which a thread is blocked gives undefined results Copyright ©: University of Illinois CS 241 Staff 38

Semaphore Operations #include <semaphore. h> int sem_post(sem_t *sem); n Unlock a semaphore n Returns

Semaphore Operations #include <semaphore. h> int sem_post(sem_t *sem); n Unlock a semaphore n Returns ¡ ¡ n 0 on success -1 on failure, sets errno (== EINVAL if semaphore doesn’t exist) Parameters ¡ sem: n n Target semaphore sem > 0: no threads were blocked on this semaphore, the semaphore value is incremented sem == 0: one blocked thread will be allowed to run Notes ¡ sem_post() is reentrant with respect to signals and may be invoked from a signal-catching function Copyright ©: University of Illinois CS 241 Staff 39

Semaphore Operations #include <semaphore. h> int sem_wait(sem_t *sem); n Lock a semaphore ¡ n

Semaphore Operations #include <semaphore. h> int sem_wait(sem_t *sem); n Lock a semaphore ¡ n Returns ¡ ¡ n Blocks if semaphore value is zero 0 on success -1 on failure, sets errno (== EINTR if interrupted by a signal) Parameters ¡ sem: n n n Target semaphore sem > 0: thread acquires lock sem == 0: thread blocks Copyright ©: University of Illinois CS 241 Staff 40

Semaphore Operations #include <semaphore. h> int sem_trywait(sem_t *sem); n Test a semaphore’s current condition

Semaphore Operations #include <semaphore. h> int sem_trywait(sem_t *sem); n Test a semaphore’s current condition ¡ n Returns ¡ ¡ n Does not block 0 on success -1 on failure, sets errno (== AGAIN if semaphore already locked) Parameters ¡ sem: n n n Target semaphore sem > 0: thread acquires lock sem == 0: thread returns Copyright ©: University of Illinois CS 241 Staff 41

Example: bank balance n Want shared variable balance to be protected by semaphore when

Example: bank balance n Want shared variable balance to be protected by semaphore when used in: ¡ ¡ decshared – a function that decrements the current value of balance incshared – a function that increments the balance variable. Copyright ©: University of Illinois CS 241 Staff 42

Example: bank balance int decshared() { while (sem_wait(&balance_sem) == -1) if (errno != EINTR)

Example: bank balance int decshared() { while (sem_wait(&balance_sem) == -1) if (errno != EINTR) return -1; balance--; return sem_post(&balance_sem); } int incshared() { while (sem_wait(&balance_sem) == -1) if (errno != EINTR) return -1; balance++; return sem_post(&balance_sem); } Copyright ©: University of Illinois CS 241 Staff 43

Summary n n n Semaphores Semaphore implementation POSIX Semaphore Programming with semaphores Next time:

Summary n n n Semaphores Semaphore implementation POSIX Semaphore Programming with semaphores Next time: solving real problems with semaphores & more Copyright ©: University of Illinois CS 241 Staff 44