Università degli studi di Udine Sistemi operativi – Operating Systems Synchronization Università degli studi di Udine Sistemi operativi – Operating Systems Synchronization Synchronization primitives HW primitives Atomic operations Low-level synchronization primitives Exclusive locks, rwlocks, seq. locks, non-blocking data structures Locking strategies and issues High-level synchronization primitives Synchronization patterns Classical problems Deadlock management Università degli studi di Udine Sistemi operativi – Operating Systems Concurrency Multiple applications (multiprogramming) independent application processes unaware of others competition on shared resources cooperating application processes indirectly aware of others cooperation by sharing resources synchronization Parallel applications processes/threads directly aware of others cooperation by communication (messages or shared variables) synchronization Università degli studi di Udine Sistemi operativi – Operating Systems Concurrence issues Race conditions final results depend on execution order Starvation some task waits indefinitely Deadlock a circular waiting dependency prevents work to proceed
42
Embed
Synchronization patterns Classical problems Deadlock ... · allow only one task to proceed, others must wait several tasks compete to acquire a lock only one wins (acquires the lock)
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
� Synchronization primitives
� HW primitives
� Atomic operations
� Low-level synchronization primitives
� Exclusive locks, rwlocks, seq. locks, non-blocking data structures
� Locking strategies and issues
� High-level synchronization primitives
� Synchronization patterns
� Classical problems
� Deadlock management
Università degli studi di Udine Sistemi operativi – Operating Systems
Concurrency
� Multiple applications (multiprogramming)
� independent application
� processes unaware of others
� competition on shared resources
� cooperating application
� processes indirectly aware of others
� cooperation by sharing resources
� synchronization
� Parallel applications
� processes/threads directly aware of others
� cooperation by communication (messages or shared variables)
� synchronization
Università degli studi di Udine Sistemi operativi – Operating Systems
Concurrence issues
� Race conditions
� final results depend on execution order
� Starvation
� some task waits indefinitely
� Deadlock
� a circular waiting dependency prevents work to proceed
Università degli studi di Udine Sistemi operativi – Operating Systems
Race condition
� Results depend on the order of the execution
a=a+b
process A
b=a+b
process B
shared vars
a=1 ; b=2
a=? ; b=?a=3 ; b=5
a=4 ; b=3
a=3 ; b=3
Università degli studi di Udine Sistemi operativi – Operating Systems
Race condition
� Results depend on the order of the execution
local tmpA
tmpA=count
tmpA=tmpA+1
count=tmpA
process A
local tmpB
tmpB=count
tmpB=tmpB+1
count=tmpB
process B
shared var
count=0
count=?count=2 OK
count=1 NO
Università degli studi di Udine Sistemi operativi – Operating Systems
Mutual exclusion
� Group of instructions must be executed atomically
local tmpA
tmpA=count
tmpA=tmpA+1
count=tmpA
process A
local tmpB
tmpB=count
tmpB=tmpB+1
count=tmpB
process B
shared var
count=0
count=2
BeginSection / Lock
EndSection / Unlock
Critical
Section
BeginSection / Lock
EndSection / Unlock
Critical
Section
Università degli studi di Udine Sistemi operativi – Operating Systems
Starvation
D C B A
Execute
E
ready processes RUN
D E C B
Execute
A
ready processes RUN
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock
Task A Task B
Task D Task C
wait
wait
waitwait
Wrong synchronization!
System is blocked!
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
Synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
� HW primitives
� processor instructions
� usually not privileged
� Low-level synchronization primitives
� built on top of HW primitives
� do not require scheduler intervention� can be implemented at user level
� High-level synchronization primitives
� built on top of low-level primitives
� interact with scheduler� from user level, imply syscalls
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
HW primitives
Synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
HW primitives
� Atomic Read, atomic Write� not practical
� requires N accesses to synchronize N tasks� requires unique IDs for tasks
� Atomic Read-Modify-Write� allows to implement simple spin-locks
� implementation independent of involved tasks� no "unique IDs" requirement
� clever implementation can reduce contention� ticket, array-based, queue-based locks
� Load-Link and Store-Conditional� do not require a double memory access in a single instruction
Università degli studi di Udine Sistemi operativi – Operating Systems
HW primitives
� Atomic Read-Modify-Write
� minimal feature to implement practical locks
� Test-and-Set
� Read-and-Increment
� x86: lock xadd
� Exchange
� x86: xchg
� ARM:swp
� deprecated since ARMv6
� Others:
� fetch_and_sub, fetch_and_or, ...
int Test-and-Set(int *ptr){ int old = *ptr; *ptr = 1; return old;}
int Read-and-Increment(int *ptr, int inc){ int old = *ptr; *ptr = old + incr; return old;}
int Exchange(int *ptr, int new){ int old = *ptr; *ptr = new; return old;}
pseudo-code
atomic
atomic
atomic
Università degli studi di Udine Sistemi operativi – Operating Systems
HW primitives
� Atomic Read-Test-Modify-Write
� allows wait-free and lock-free synchronization
� Compare-and-Exchange or Compare-and-Swap (CAS)
� x86: lock cmpxchg
int Compare-Exchange(int *ptr, int testval, int new){ int old = *ptr; if (old == testval) *ptr = new; return old;}
pseudo-code
atomic
Università degli studi di Udine Sistemi operativi – Operating Systems
HW primitives
� Load-Link and Store-Conditional
� do not require a double memory access in a single instruction
� MIPS:
� ll, sc
� ARM:
� ldrex, strex
int LL(int *ptr){ remember this access return *ptr;}
int SC(int *ptr, int val){ if (this cpu has executed LL on ptr) { if (*ptr written since the last LL performed by this cpu) return SC_FAILURE; /* fail */ else { /* *ptr has not changed */ *ptr = val; return SC_SUCCESS; /* success */ } } unspecified behavior}
pseudo-code
atomic
atomic
Università degli studi di Udine Sistemi operativi – Operating Systems
� Load-Link and Store-Conditional
� do not require a double memory access in a single instruction
� MIPS:
� ll, sc
� ARM:
� ldrex, strex
HW primitives
atomic
pseudo-code
atomic
LL x
Modify x
SC x
failure � operations not atomic: retry
LL x
Modify x
SC x
success � operations was atomic: go on
PROCESSOR A PROCESSOR B
Atomic Read-Modify-Write
Università degli studi di Udine Sistemi operativi – Operating Systems
HW primitives: summary
� Atomic accesses:
� Read-Modify-Write operations
� fetch_and_add, fetch_and_sub, fetch_and_or, fetch_and_and, ...� perform the operation suggested by the name, and return the old value
3. test the current value of flag� �if A data not changed: ok to proceed; else, repeat the operation
� problem:� after task1.1, task2 stores B to flag
� before task1.3, task2 changes data and store A to flag� � task1 is not aware of changes
� data inconsistency
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
struct NodeType {
Datatype data;
struct NodeType *next;
};
struct NodeType *Head;
void init() {
Head = NULL;
}
void push(struct NodeType *n) {
do {
n->next = Head;
} while (CAS(&Head, n->next, n) != n->next);
}
struct NodeType *pop() {
struct NodeType *n, *next;
do {
n = Head; next = n->next;
} while (n != NULL && CAS(&Head, n, next) != n);
return n;
}
Lock free
Head
A B C NULL
top of the stack
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
TASK1: TASK2:
n = Head;
n1 = Head;
CAS(&Head, n1, n1->next)
n2 = Head;
CAS(&Head, n2, n2->next)
n1->next = Head;
CAS(&Head, n1->next, n1)
CAS(&Head, n, n->next)
Head
A B C NULL
n
n1
n2
n = pop();
n1 = pop();
n2 = pop();
push(n1);
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
TASK1: TASK2:
n = Head;
n1 = Head;
CAS(&Head, n1, n1->next)
n2 = Head;
CAS(&Head, n2, n2->next)
n1->next = Head;
CAS(&Head, n1->next, n1)
CAS(&Head, n, n->next)
Head
A B C NULL
n
n1
n2
n = pop();
n1 = pop();
n2 = pop();
push(n1);
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
TASK1: TASK2:
n = Head;
next = n->next;
n1 = Head;
CAS(&Head, n1, n1->next)
n2 = Head;
CAS(&Head, n2, n2->next)
n1->next = Head;
CAS(&Head, n1->next, n1)
CAS(&Head, n, n->next)
Head
A B C NULL
top of the stack
n = pop();
n1 = pop();
n2 = pop();
push(n1);
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
TASK1: TASK2:
n = Head;
next = n->next;
n1 = Head;
CAS(&Head, n1, n1->next)
n2 = Head;
CAS(&Head, n2, n2->next)
n1->next = Head;
CAS(&Head, n1->next, n1)
CAS(&Head, n, n->next)
n = pop();
n1 = pop();
n2 = pop();
push(n1);
Head
A B C NULL
n
n1
n2
next
CAS is successful
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free stack (example): ABA
� Do not reuse nodes
� task2:
n1 = pop(); n1 = pop();
n2 = pop(); n2 = pop();
push(n1); n3 = new node
n3.data = n1.data;
push(n3);
� When can n1 be freed?
� after n1 is released, another task can obtain that memory as a new
node
� � ABA can happen
Università degli studi di Udine Sistemi operativi – Operating Systems
ABA solutions
� Deferred reclamation
� Do not reuse nodes
� Don't recycle the memory “too soon”
� Garbage collector
� Hazard pointers
� Read-Copy-Update
� Use the same CAS for 2 pointers
� needs a double-word CAS
� Tagged pointers
� some bits of a pointer are used as a counter
� beware the wrap-around
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free list (example)
struct NodeType {
Datatype data;
struct NodeType *next;
};
struct NodeType *Head, *Tail;
void init() {
NodeType *dummynode;
dummynode = malloc(sizeof struct NodeType);
dummynode->next = NULL;
Head = Tail = dummynode;
}
void insert(struct NodeType *n) {
struct NodeType *tmp;
n->next = NULL;
tmp = Tail;
tmp->next = n;
Tail = n;
}
struct NodeType *remove() {
struct NodeType *n;
n = Head->next;
if (n != NULL) {
Head = n;
}
return n;
}
Head
NULL
dummy node
Tail
first node
Not concurrent
discard dummy node;
n becomes the new dummy node Not concurrent:
a lock is needed to make push and
pop atomic
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free list (example)
struct NodeType {
Datatype data;
struct NodeType *next;
};
struct NodeType *Head, *Tail;
void init() {
NodeType *dummynode;
dummynode = malloc(sizeof struct NodeType);
dummynode->next = NULL;
Head = Tail = dummynode;
}
void insert(struct NodeType *n) {
struct NodeType *tmp;
n->next = NULL;
tmp = Tail;
tmp->next = n;
Tail = n;
}
struct NodeType *remove() {
struct NodeType *n;
n = Head->next;
if (n != NULL) {
Head = n;
}
return n;
}
Head
NULL
dummy node
Tail
first node
Not concurrent:
a lock is needed to make push and
pop atomic
after every step, the list must remain consistent:
- nodes are all linked
- Head points to the dummy node
- Tail is after Head
concurrent tasks must “cooperate”
Università degli studi di Udine Sistemi operativi – Operating Systems
Lock-free list (example)
Head
NULL
dummy node
Tail
first node
struct NodeType {
Datatype data;
struct NodeType *next;
};
struct NodeType *Head, *Tail;
void init() {
NodeType *dummynode;
dummynode = malloc(sizeof struct NodeType);
dummynode->next = NULL;
Head = Tail = dummynode;
}
void insert(struct NodeType *n) {
struct NodeType *tmp, *ntmp;
n->next = NULL;
do {
tmp = Tail;
ntmp = tmp->next;
if (Tail != tmp) continue;
if (ntmp != NULL) {
CAS(&Tail, tmp, tmp->next);
continue;
}
} while (CAS(&tmp->next, NULL, n) != NULL);
CAS(&Tail, tmp, n);
}
struct NodeType *remove() {
struct NodeType *n, *h, *t;
do {
h = Head;
t = Tail;
n = h->next;
if (Head != h) continue;
if (n == NULL)
break;
if (h == t) {
CAS(&Tail, t, n);
continue;
}
} while (CAS(&Head, h, n) != h);
return n;
}Lock free
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
High-level
synchronization primitives
Synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
� Semaphores
� Semaphores (Counting semaphores)
� Binary semaphores
� Mutexes
� Condition variables
� Monitors
� Deferred processing
� e.g., Read-Copy-Update (RCU)
High-level synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
� Semaphore
� Integer variable
� Operations (all atomic)
� initialize
� set the initial value� an arbitrary non-negative value
� semWait (also: P)
� decrement value; if the result is negative, then suspend the calling processif suspended, the process is stored on a list associated to the semaphore
� used to enter in a critical section
� semSignal (also: V)
� increment value; if the result is non-positive, then resume a suspended processthe process to be resumed is read from the list associated to the semaphore
� used to leave a critical section
High-level synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
Semaphores
� Strong semaphore
� task are resumed in FIFO order
� fair implementation
� Weak semaphore
� no order is imposed on task reactivations
Università degli studi di Udine Sistemi operativi – Operating Systems
Semaphores
� Binary semaphore
� Semaphore that can only assume values 0 or 1
� initialize
� Only 0 or 1 are valid initial values
� semSignal
� if value is 0, then resume a waiting process (if any)the process to be resumed is read from the list associated to the semaphore
� semWait
� if value is 0, then suspend process, else decrement valueif suspended, the process is stored on a list associated to the semaphore
Università degli studi di Udine Sistemi operativi – Operating Systems
Semaphore implementation (example)
typedef struct semaphore_t { int count; int lock; QUEUE suspended;} semaphore;
void semWait(semaphore *sem){ lock(&sem->lock); sem->count--; if (sem->count < 0) { place this process in sem->suspended unlock(&sem->lock); suspend this process } else { unlock(&sem->lock); }}
void semSignal(semaphore *sem){ lock(&sem->lock); sem->count++; if ( sem->count <= 0 ) { remove a process P from sem->suspended place process P on the ready list } unlock(&sem->lock);}
kernel-level
operations
access to
sem must
be atomic
spinlock
protected
section
Università degli studi di Udine Sistemi operativi – Operating Systems
High-level synchronization primitives
� Mutex
� Similar to a binary semaphore but
only the task owning the mutex can unlock it
� The same semantic of low-level locks
� but scheduler is into play
� Reentrant (or recursive) mutex
� a task can acquire the mutex multiple times
� multiple levels of ownership
� must be released the same number of times
Università degli studi di Udine Sistemi operativi – Operating Systems
High-level synchronization primitives
� Monitor
� abstract data type
� accessible only through “access procedures” (all atomic and exclusive)
� Only a task can access the monitor at a time
� Object oriented approach
� e.g., in C++ a monitor can be implemented with a class where:
� there is a reentrant mutex as a field
� all methods get the mutex on entry
� all methods release the mutex on exit
� signaling is realized with explicit condition variables
Università degli studi di Udine Sistemi operativi – Operating Systems
� Condition variables
� Condition to test
� Operations (all atomic)
� cond_wait
� sleep until another task calls signal or broadcast
� cond_notify (also: signal)
� wake up a waiting task
� cond_notifyAll (also: broadcast)
� wake up all waiting tasks
High-level synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
Condition variables
� Using condition variables
� on waiting: use a loop
� condition set by signaling task may be no more true
� another task could have changed the condition after the signaling
� MESA semantic
� Hoare semantic:
� after the signaling the waiting thread is woken up
� nobody else gets control on the condition
� hard to implement (never used in practice)
� a lock (or a mutex) is required
� prevents the race condition:
� sequence: test (done is 0), set (done becomes 1), cond_signal, cond_wait
� the signaling is lost � the waiting thread is never woken up
task A
task B
Università degli studi di Udine Sistemi operativi – Operating Systems
void cond_wait(cond_t *cond_var){ atomically add this task to cond_var->waiting unlock(&cond_var->lock); suspend this task lock(&cond_var->lock);}
void cond_notify(cond_t *cond_var){ atomically remove a task T from cond_var->waiting resume T (place T on the ready list)}
void cond_notify_all(cond_tr *cond_var){ for each task T in cond_var->waiting { atomically remove a task T from cond_var->waiting resume T (place T on the ready list) }}
Università degli studi di Udine Sistemi operativi – Operating Systems
Università degli studi di Udine Sistemi operativi – Operating Systems
Condition variables pseudocode (example 2)
typedef struct { QUEUE waiting;} cond_t;
void cond_wait(cond_t *cond_var, lock_t *lck){ atomically add this task to cond_var->waiting unlock(lck); suspend this task lock(lck);}
void cond_notify(cond_t *cond_var, lock_t *lck){ atomically remove a task T from cond_var->waiting resume T (place T on the ready list)}
void cond_notify_all(cond_t *cond_var, lock_t *lck){ for each task T in cond_var->waiting { atomically remove a task T from cond_var->waiting resume T (place T on the ready list) }}
Università degli studi di Udine Sistemi operativi – Operating Systems
Università degli studi di Udine Sistemi operativi – Operating Systems
Dining philosophers
� No more than 4 philosophers can try to acquire forks
think();
semWait(fork[1]);semWait(fork[0]);
eat();
semSignal(fork[1]);semSignal(fork[0]);
L-philosopher 0
think();
semWait(fork[2]);semWait(fork[1]);
eat();
semSignal(fork[2]);semSignal(fork[1]);
L-philosopher 1
think();
semWait(fork[3]);semWait(fork[2]);
eat();
semSignal(fork[3]);semSignal(fork[2]);
L-philosopher 2
think();
semWait(fork[4);semWait(fork[3]);
eat();
semSignal(fork[4]);semSignal(fork[3]);
L-philosopher 3
think();
semWait(fork[4);semWait(fork[0]);
eat();
semSignal(fork[0]);semSignal(fork[4]);
R-philosopher 4
ph 4 is blocked by ph 3
Università degli studi di Udine Sistemi operativi – Operating Systems
Dining philosophers
think();
semWait(fork[1]);semWait(fork[0]);
eat();
semSignal(fork[1]);semSignal(fork[0]);
L-philosopher 0
think();
semWait(fork[2]);semWait(fork[1]);
eat();
semSignal(fork[2]);semSignal(fork[1]);
L-philosopher 1
think();
semWait(fork[3]);semWait(fork[2]);
eat();
semSignal(fork[3]);semSignal(fork[2]);
L-philosopher 2
think();
semWait(fork[4);semWait(fork[3]);
eat();
semSignal(fork[4]);semSignal(fork[3]);
L-philosopher 3
think();
semWait(fork[4);semWait(fork[0]);
eat();
semSignal(fork[0]);semSignal(fork[4]);
R-philosopher 4
think();
semWait(fork[1]);semWait(fork[0]);
eat();
semSignal(fork[1]);semSignal(fork[0]);
think();
semWait(fork[2]);semWait(fork[1]);
eat();
semSignal(fork[2]);semSignal(fork[1]);
think();
semWait(fork[3]);semWait(fork[2]);
eat();
semSignal(fork[3]);semSignal(fork[2]);
think();
semWait(fork[4);semWait(fork[3]);
eat();
semSignal(fork[4]);semSignal(fork[3]);
think();
semWait(fork[4);semWait(fork[0]);
eat();
semSignal(fork[0]);semSignal(fork[4]);
ph 3 is blocked by ph 4
ph 0 is blocked by ph 4
ph 3 is blocked by ph 4
ph 4 is blocked by ph 0
� No more than 4 philosophers can try to acquire forks
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
Deadlock management
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock conditions
� Mutual exclusion.� A resource can be assigned only at a fixed finite number of processes at a
time. No other processes may access a resource unit that has reached the
maximum number of assignations.� Needed (to enforce synchronization)
� No preemption.� No resource can be forcibly removed from a process holding it.� Difficult to avoid (a rollback is needed to implement resource preemption)
� Hold and wait.� A process may hold allocated resources while awaiting assignment of other
resources.
� Circular wait.� A closed chain of processes exists, such that each process holds at least one
resource needed by the next process in the chain
Deadlock is possible
Università degli studi di Udine Sistemi operativi – Operating Systems
Resources
� Swappable space
� Devices
� physical drives
� files
� Main memory blocks
� Internal resources
� I/O interrupts handling
Required asynchronously by
independent processes
Università degli studi di Udine Sistemi operativi – Operating Systems
Resource allocation graph
B R1
Task requires Resource
Task Resource
Task holds Resource
Task Resource
A B has to wait until A will release R1
B
R1
A
R2
circular dependency: deadlock
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock handling
� Prevention
� make deadlock not possible
� Avoidance
� disallow operations that may lead to a deadlock
� Detection
� periodically check for deadlock and recover
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock prevention
� Disallow hold-and-wait� all the needed resources must be required simultaneously� a process is blocked until all the required resources are available� inefficient
� a process must acquire resources needed only for small time intervals or actually not
needed
� Allow preemption� when a request is refused, a process must release all its resources� OS may request a process to release resources� practical only for resources with an easily restored state (e.g., processor)
� Disallow circular waits� define an ordering on resources� a process that owns a resource R can request a resource Q only if ord(R) < ord(Q)� disallows incremental resource request
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock avoidance
� Evaluate resource requests
� grant a resource request only if a deadlock cannot occur
� OS must know all the future requests
� banker's algorithm (Dijkstra)
Università degli studi di Udine Sistemi operativi – Operating Systems
Deadlock detection
� Periodically check for deadlock
� grant resource requests whenever possible
� if a deadlock is detected
� kill all deadlocked processes
� most common approach
� successively abort deadlocked processes (until deadlock no longer exist)
� selection order can be a key factor
� rollback all deadlocked processes to a previous state
� backup and restore mechanism must be implemented
� force a deadlocked process to release resources
� preemption
� rollback the process to a point prior the resource acquisition
Università degli studi di Udine Sistemi operativi – Operating Systems
Banker's algorithm
� For a single resource type
� Process
� resources used
� resources needed
� Available resources
� grant request only if it will lead to a safe state
� safe state:
� there exist at least one process that still needs less resources than available
� unsafe state
� deadlock is possible (no-deadlock cannot be ensured)
Università degli studi di Udine Sistemi operativi – Operating Systems
Banker's algorithm
Process A 0 15
Allocated Needed
Process B 0 7
Process C 0 4
Process D 0 12
Available 20
Process A 8 7
Allocated Needed
Process B 4 3
Process C 1 3
Process D 6 6
Available 1
unsafe: with available resources no process
is guaranteed to terminate
� For a single resource type
Università degli studi di Udine Sistemi operativi – Operating Systems
Banker's algorithm
Process A 0 15
Allocated Needed
Process B 0 7
Process C 0 4
Process D 0 12
Available 20
Process A 7 8
Allocated Needed
Process B 4 3
Process C 2 2
Process D 5 7
Available 2
safe: with available resources process C can
surely terminate
� For a single resource type
Università degli studi di Udine Sistemi operativi – Operating Systems
Banker's algorithm
� For a single resource type
� safe state:
� � i � Needed(i) < Available
Needed(i): resources still needed by process i
Available: resources still available on the system
Università degli studi di Udine Sistemi operativi – Operating Systems
Banker's algorithm
� For several resource types
� replicate information for each resource type
Process A 0 15
Allocated Needed
Process B 0 7
Process C 0 4
Process D 0 12
Available 20
0 1
Allocated Needed
0 2
0 4
0 1
Available 4
0 3
Allocated Needed
0 7
0 4
0 9
Available 10
Type-1 Type-2 Type-3
� safe state:
� i �� � j Needed(i,j) < Available(j)
Needed(i,j): resources of type j still needed by process i
Available(j): resources of type j still available on the system
Università degli studi di Udine Sistemi operativi – Operating Systems
Synchronization
User level
(POSIX)
synchronization primitives
Università degli studi di Udine Sistemi operativi – Operating Systems
GCC builtins for atomic accesses
� Read-Modify-Write operations
� __sync_fetch_and_add(type *ptr, type value);
� __sync_fetch_and_sub(type *ptr, type value);
� __sync_fetch_and_or(type *ptr, type value);
� __sync_fetch_and_and(type *ptr, type value);
� __sync_fetch_and_xor(type *ptr, type value);
� __sync_fetch_and_nand(type *ptr, type value);
� perform the operation suggested by the name, and return the old
value;
� imply a full memory barrier
Università degli studi di Udine Sistemi operativi – Operating Systems
GCC builtins for atomic accesses
� Read-Modify-Write operations
� __sync_add_and_fetch(type *ptr, type value);
� __sync_sub_and_fetch(type *ptr, type value);
� __sync_or_and_fetch(type *ptr, type value);
� __sync_and_and_fetch(type *ptr, type value);
� __sync_xor_and_fetch(type *ptr, type value);
� __sync_nand_and_fetch(type *ptr, type value);
� perform the operation suggested by the name, and return the new
value;
� imply a full memory barrier
Università degli studi di Udine Sistemi operativi – Operating Systems
GCC builtins for atomic accesses
� Read-Modify-Write operations
� __sync_lock_test_and_set(type *ptr, type value);
� perform an atomic exchange: writes value into *ptr and returns the previous
contents of *ptr;
� implies an acquire barrier
� Read-Test-Modify-Write operations
� __sync_val_compare_and_swap(type *ptr, type oldval, type newval);
� __sync_bool_compare_and_swap(type *ptr, type oldval, type newval);
� perform atomic compare-and-swap: if the current value of *ptr is oldval,
then write newval into *ptr;
� __sync_val_compare_and_swap returns the old value of *ptr
� __sync_bool_compare_and_swap returns true if the comparison is successful
� imply a full memory barrier
Università degli studi di Udine Sistemi operativi – Operating Systems
GCC builtins for atomic accesses
� Others:
� __sync_lock_release(type *ptr);
� Writes 0 to *ptr;
� implies a release barrier
� __sync_synchronize();
� Issues a full memory barrier
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� Low-level primitives
� spinlocks
� High-level primitives
� semaphores
� mutexes
� reader-writer locks
� condition variables
� barriers
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� Low-level primitives
� spinlocks
� type
� pthread_spinlock_t
� operations:
� pthread_spin_init
� pthread_spin_destroy
� pthread_spin_lock
� pthread_spin_unlock
� pthread_spin_trylock
initialization
deallocation
locking
unlocking
tentative locking
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� High-level primitives
� semaphores
� type
� sem_t
� operations:
� sem_init
� sem_destroy
� sem_getvalue
� sem_wait
� sem_timedwait
� sem_trywait
� sem_post
initialization
deallocation
waiting
unlocking
tentative waiting
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� High-level primitives
� mutexes
� type
� pthread_mutex_t
� operations:
� pthread_mutex_init
� pthread_mutex_destroy
� pthread_mutex_lock
� pthread_mutex_unlock
� pthread_mutex_trylock
initialization
deallocation
locking
unlocking
tentative locking
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� High-level primitives
� reader-writer locks
� type
� pthread_rwlock_t
� operations:
� pthread_rwlock_init
� pthread_rwlock_destroy
� pthread_rwlock_rdlock
� pthread_rwlock_wrlock
� pthread_rwlock_unlock
� pthread_rwlock_tryrdlock
� pthread_rwlock_trywrlock
initialization
deallocation
locking
unlocking
tentative locking
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� High-level primitives
� condition variables
� type
� pthread_cond_t
� operations:
� pthread_cond_init
� pthread_cond_destroy
� pthread_cond_wait
� pthread_cond_timedwait
� pthread_cond_signal
� pthread_cond_broadcast
initialization
deallocation
waiting
notifying
Università degli studi di Udine Sistemi operativi – Operating Systems
User level (POSIX)
synchronization primitives
� High-level primitives
� barriers
� type
� pthread_barrier_t
� operations:
� pthread_barrier_init
� pthread_barrier_destroy
� pthread_barrier_wait
initialization
deallocation
waiting
Università degli studi di Udine Sistemi operativi – Operating Systems