CIS 5512 - Operating Systems Synchronization Professor Qiang Zeng Fall 2015

Preview:

Citation preview

CIS 5512 - Operating SystemsSynchronization

Professor Qiang Zeng

Fall 2015

CIS 5512 – Operating Systems 2

Previous class…

• IPC– Pipes– FIFO (named pipes)– message queues– shared memory

• Concepts– Race condition, critical section, mutual exclusion

• Synchronization primitives

CIS 5512 – Operating Systems 3

Compare different IPCs

IPC method Features

Pipes Can only be used among parent and child

FIFOs(named pipes)

Can be referred to by a string, so doesn’t have the limitation above

Message queues Unlike Pipes and FIFOs, they support message boundary and message types

Shared memory Data passing doesn’t go through kernel, so it is usually the most efficient one

Concepts: race condition, critical section, and mutual exclusion

lock();

counter++ //critical section

unlock();

What goes here?

The code below is run simultaneously in multiple threads/processesRace condition exists unless…

Big picture of synchronization primitives

Spin locks (busy-waiting locks)

Algorithms that do not rely on special instructions (Dekker’, Peterson’s, Bakery)

Algorithms based on atomic read-modify-write instructions (test-and-set, xchg)

CIS 5512 – Operating Systems 6

Solutions based on atomic read-modify-write instructions

test_and_set(int* p){ int t = *p; *p = 1; return t;}

enter_region() { while(test_and_set(&lock) == 1) ;}

leave_region() { lock = 0;}

Big picture of synchronization primitives

7

Sync. Primitives(or loosely, “locks”)

Spin locks (busy-waiting locks)

Semaphore: it contains an internal counter indicating the number of resources; API: down()/up() (or, sem_wait/sem_signal)Binary Semaphore is a special semaphore, whose counter value can only be 0 or 1; sometimes it is used as a mutex

Conditional Variables: they are used to ease concurrent programming. You have to use it with a mutex. Monitor encapsulates CV and mutex

Blocking locks

Algorithms that do not rely on special instructions (Dekker’, Peterson’s, Bakery)

Algorithms based on atomic read-modify-write instructions (test-and-set, xchg)

CIS 5512 – Operating Systems 8

Semaphore – avoids busy-waiting

// Atomicdown(S) { // or, P(), sem_wait() if(S.cnt>0) S.cnt--; else put the current process in queue; block the current process;}

// Atomicup(S) { // or, V(), sem_signal() if(any process is in S’s wait queue) remove a process from the queue; resume it; else S.cnt++;}

Using Mutexs and Semaphores:The restroom problem and the bar problem

Binary Semaphore for the restroom problem: mutual exclusion

• Customers try to enter a single-spot restroom• please write code describing the customers• Hint: Binary Semaphore, a special semaphore,

whose counter value can only be 0 or 1• Here, Binary Semaphore is used as Mutex, a

blocking lock for MUTual EXclusion

S = 1; // shared among customers (processes)

// each customer (process) does the followingdown(S); // try to enter the restroom; = lock()Use the restroom //critical sectionup(S); // leave the restroom; = unlock()

CIS 5512 – Operating Systems 11

Semaphore for the bar problem

• Capacity = 100• Many customers try to enter the bar concurrently• Please write code describing the customers• Caution: a Mutex will not work well; why?

S = 100; // shared among processes

// each process does the followingdown(S); // try to enter the barHave fun; up(S); // leave the bar

Using Semaphores:A simple signaling problem

Semaphore for signaling

• Process 0 and Process 1• How to make sure statement A in Process 0 gets

executed before statement B in Process 1• Hint: use a semaphore and initialize it as 0

S = 0; // shared

// Process 0A;up(S);

// Process 1down(S);B;

CIS 5512 – Operating Systems 14

Semaphore for signaling

• How to make sure event A1 in Process 0 occurs before B1 in Process 1, and B2 in Process 1 occurs before A2 in Process 0?

• Hint: use two semaphores

S1 = 0; // sharedS2 = 0; // shared

// Process 0A1;up(S1);down(S2);A2;

// Process 1down(S1);B1;B2;up(S2);

CIS 5512 – Operating Systems 15

Single-slot Producer-Consumer problem

• Hint:– Consumer.removeItem() has to occur after

Producer.fillSlot()– Producer.fillSlot(), once the slot is filled, has to occur

after Consumer.removeItem()S_slot = 1; // sharedS_item = 0; // shared

// Producerwhile(true) { down(S_slot); fillSlot(); up(S_item);}

// Consumerwhile(true) { down(S_item); removeItem(); up(S_slot);}

Using Semaphores:The Producer-Consumer

Problem

Acknowledgement: some slides courtesy of Dr. Brighten Godfrey

Producer-consumer problem

• Chefs cook items and put them on a conveyer belt

Waiters pick items off the belt

Producer-consumer problem

• Now imagine many chefs!

...and many waiters!

Producer-consumer problem

• A potential mess!

Producer-consumer problemChef (Producer) Waiter (Consumer)

inserts items removes items

Shared resource:bounded buffer

Efficient implementation:circular fixed-size buffer

Shared bufferChef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

What does the chef do with a

new pizza?

Where does the waiter take a pizza from?

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Insert pizza

insertPtr

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Insert pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Insert pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

removePtr

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Insert pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Insert pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

BUFFER FULL: Producer must wait!

Insert pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtrremovePtrRemove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtr

removePtr

Remove pizza

Chef (Producer) Waiter (Consumer)

Shared buffer

insertPtrremovePtr

Buffer empty: Consumer must be blocked!

Remove pizza

Chef (Producer) Waiter (Consumer)

Designing a solutionChef (Producer) Waiter (Consumer)

Wait for empty slotInsert itemSignal item arrival

Wait for item arrivalRemove item

Signal empty slot available

What synchronization do we need?

Designing a solutionChef (Producer) Waiter (Consumer)

Wait for empty slotInsert itemSignal item arrival

Wait for item arrivalRemove item

Signal empty slot available

What synchronization do we need?

Mutex(shared buffer)

Designing a solutionChef (Producer) Waiter (Consumer)

Wait for empty slotInsert itemSignal item arrival

Wait for item arrivalRemove item

Signal empty slot available

What synchronization do we need?

Semaphore(# empty slots)

Designing a solutionChef (Producer) Waiter (Consumer)

Wait for empty slotInsert itemSignal item arrival

Wait for item arrivalRemove item

Signal empty slot available

What synchronization do we need?

Semaphore(# filled slots)

Producer-Consumer Code

buffer[ insertPtr ] = data;

insertPtr = (insertPtr + 1) % N;

result = buffer[removePtr];

removePtr = (removePtr +1) % N;

Critical Section: move insert pointer

Critical Section: move remove pointer

Producer-Consumer Code

sem_wait(&slots);mutex_lock(&mutex);buffer[ insertPtr ] =

data;insertPtr = (insertPtr

+ 1) % N;mutex_unlock(&mutex);sem_post(&items);

sem_wait(&items);mutex_lock(&mutex);result =

buffer[removePtr];removePtr = (removePtr

+1) % N;mutex_unlock(&mutex);sem_post(&slots);

Block if there are no free slots

Block if there are no items

to take

Counting semaphore – check and decrement the number of free slots

Counting semaphore – check and decrement the number of available items

Done – increment the number of available items

Done – increment the number of free slots

Consumer Pseudocode: getItem()

sem_wait(&items);pthread_mutex_lock(&mutex);result = buffer[removePtr];removePtr = (removePtr +1) % N;pthread_mutex_unlock(&mutex);sem_signal(&slots);

Error checking/EINTR handling not shown

Producer Pseudocode: putItem(data)

sem_wait(&slots);pthread_mutex_lock(&mutex);buffer[ insertPtr ] = data;insertPtr = (insertPtr + 1) % N;pthread_mutex_unlock(&mutex);sem_signal(&items);

Error checking/EINTR handling not shown

Readers-Writers Problem

Readers-Writers Problem

• Mutual exclusion problem• Problem statement:

– Reader threads only read the object– Writer threads modify the object– Writers must have exclusive access to the object– Unlimited number of readers can access the object

• Occurs frequently in real systems, e.g.,– Online airline reservation system– Multithreaded caching Web proxy

void writer(void) { while (1) { sem_wait(&w);

/* Critical section */ /* Writing here */

sem_post(&w); }}

Writers:

int readcnt; /* Initially = 0 */sem_t mutex, w; /* Both initially = 1 */

Shared:

Solution favoring readers

(full codeonline)

void reader(void) { while (1) { sem_wait(&mutex); readcnt++; if (readcnt == 1) /* First reader in */ sem_wait(&w); /* Lock out writers */ sem_post(&mutex);

/* Main critical section */ /* Reading would happen here */

sem_wait(&mutex); readcnt--; if (readcnt == 0) /* Last out */ sem_post(&w); /* Let in writers */ sem_post(&mutex); }}

Readers:

Solution favoring readers

Summary

• Synchronization: more than just locking a critical section

• Semaphores useful for counting available resources– sem_wait(): wait for resource only if none available– sem_post(): signal availability of another resource

• Multiple semaphores / mutexes can work together to solve complex problems