You are on page 1of 40

Xinu Semaphores

Concurrency

• An important and fundamental feature in modern operating


systems is concurrent execution of processes/threads. This
feature is essential for the realization of multiprogramming,
multiprocessing, distributed systems, and client-server
model of computation.
• Concurrency encompasses many design issues including
communication and synchronization among processes,
sharing of and contention for resources.
• In this discussion we will look at the various design
issues/problems and the wide variety of solutions available.

01/07/2022 Page 2
Principles of Concurrency
• Interleaving and overlapping the execution of
processes.
• Consider two processes P1 and P2 executing the
function echo:
{
input (in, keyboard);
out = in;
output (out, display);
}

01/07/2022 Page 3
...Concurrency (contd.)
• P1 invokes echo, after it inputs into in , gets interrupted (switched). P2
invokes echo, inputs into in and completes the execution and exits. When
P1 returns in is overwritten and gone. Result: first ch is lost and second ch
is written twice.
• This type of situation is even more probable in multiprocessing systems
where real concurrency is realizable thru’ multiple processes executing on
multiple processors.
• Solution: Controlled access to shared resource
– Protect the shared resource : in buffer; “critical resource”
– one process/shared code. “critical region”

01/07/2022 Page 4
Interactions among processes
• In a multi-process application these are the various degrees of
interaction:
1. Competing processes: Processes themselves do not share anything.
But OS has to share the system resources among these processes
“competing” for system resources such as disk, file or printer.
Co-operating processes : Results of one or more processes may be
needed for another process.
2. Co-operation by sharing : Example: Sharing of an IO buffer. Concept of
critical section. (indirect)
3. Co-operation by communication : Example: typically no data sharing,
but co-ordination thru’ synchronization becomes essential in certain
applications. (direct)

01/07/2022 Page 5
Interactions ...(contd.)

• Among the three kinds of interactions indicated by 1, 2


and 3 above:
• 1 is at the system level: potential problems : deadlock
and starvation.
• 2 is at the process level : significant problem is in
realizing mutual exclusion.
• 3 is more a synchronization problem.
• We will study mutual exclusion and synchronization
here, and defer deadlock, and starvation for a later time.

01/07/2022 Page 6
Mutual exclusion problem
• Successful use of concurrency among processes
requires the ability to define critical sections and
enforce mutual exclusion.
• Critical section : is that part of the process code that
affects the shared resource.
• Mutual exclusion: in the use of a shared resource is
provided by making its access mutually exclusive
among the processes that share the resource.
• This is also known as the Critical Section (CS) problem.

01/07/2022 Page 7
Software Solutions: Algorithm 1
• Process 0 1
•• ... ...
•• while
while turn
turn !=
!= 0
1 do
do
•• nothing;
nothing;
• // busy waiting
• // busy waiting
• < Critical Section>
• < Critical Section>
• turn = 1;
•• turn
... = 0;
•Problems
... : Strict alternation, Busy Waiting

01/07/2022 Page 8
Algorithm 2
• PROCESS 0 1
•• ...
...
•• flag[0]
flag[1] == TRUE;
TRUE;
•• while flag[1] do nothing;
while flag[0] do nothing;
• <CRITICAL SECTION>
• <CRITICAL SECTION>
• flag[0] = FALSE;
• flag[1] = FALSE;
PROBLEM : Potential for deadlock, if one of the processes fail
within CS.

01/07/2022 Page 9
Algorithm 3
• Combined shared variables of algorithms 1 and 2.
• Process Pi
do {
flag [i]:= true;
turn = j;
while (flag [j] and turn = j) ;
critical section
flag [i] = false;
remainder section
} while (1);
• Solves the critical-section problem for two processes.

01/07/2022 Page 10
Semaphores
• Think about a semaphore as a class
• Attributes: semaphore value, Functions: init, wait,
signal
• Support provided by OS
• Considered an OS resource, a limited number
available: a limited number of instances (objects) of
semaphore class is allowed.
• Can easily implement mutual exclusion among any
number of processes.

01/07/2022 Page 11
Critical Section of n Processes

• Shared data:
Semaphore mutex; //initially mutex = 1

• Process Pi:

do {
mutex.wait();
critical section
mutex.signal();
remainder section
} while (1);

01/07/2022 Page 12
Semaphore Implementation
• Define a semaphore as a class:
class Semaphore
{ int value; // semaphore value
ProcessQueue L; // process queue
//operations
wait()
signal()
}
• In addition, two simple utility operations:
– block() suspends the process that invokes it.
– Wakeup() resumes the execution of a blocked process P.

01/07/2022 Page 13
Semantics of wait and signal
• Semaphore operations now defined as
S.wait():
S.value--;
if (S.value < 0) {
add this process to S.L;
block(); // block a process
}

S.signal():
S.value++;
if (S.value <= 0) {
remove a process P from S.L;
wakeup(); // wake a process
}

01/07/2022 Page 14
Semaphores for CS
• Semaphore is initialized to 1. The first process that executes a
wait() will be able to immediately enter the critical section (CS).
(S.wait() makes S value zero.)
• Now other processes wanting to enter the CS will each execute
the wait() thus decrementing the value of S, and will get
blocked on S. (If at any time value of S is negative, its absolute
value gives the number of processes waiting blocked. )
• When a process in CS departs, it executes S.signal() which
increments the value of S, and will wake up any one of the
processes blocked. The queue could be FIFO or priority queue.

01/07/2022 Page 15
Two Types of Semaphores

• Counting semaphore – integer value can


range over an unrestricted domain.
• Binary semaphore – integer value can
range only between 0 and 1; can be
simpler to implement. ex: nachos
• Can implement a counting semaphore
using a binary semaphore.

01/07/2022 Page 16
Semaphore for Synchronization

• Execute B in Pj only after A executed in Pi


• Use semaphore flag initialized to 0
• Code:
Pi Pj
 
A flag.wait()
flag.signal() B

01/07/2022 Page 17
Classical Problems of Synchronization
• Bounded-Buffer Problem

• Readers and Writers Problem

• Dining-Philosophers Problem

01/07/2022 Page 18
Producer/Consumer problem
• Consumer
Producer
repeat
produce
while (in item
<= out)
v; nop;
b[in]
w = b[out];
= v;
in = =inout
out + 1;+ 1;
forever; w;
consume
forever;

01/07/2022 Page 19
Solution for P/C using Semaphores
• Producer • Consumer
• repeat • repeat
• produce item v; • while (in <= out) nop;
• MUTEX.wait(); • MUTEX.wait();
• b[in] = v; • w = b[out];
• in = in + 1; • out = out + 1;
• MUTEX.signal(); • MUTEX.signal();
• forever; • consume w;
• forever;
• Ans: Consumer will busy-
• What if Producer is slow or wait at the while statement.
late?

01/07/2022 Page 20
P/C: improved solution
• Producer • Consumer
repeat repeat
produce item v; AVAIL.wait();
MUTEX.wait(); MUTEX.wait();
b[in] = v; w = b[out];
in = in + 1; out = out + 1;
MUTEX.signal(); MUTEX.signal();
AVAIL.signal(); consume w;
forever; forever;

• What will be the initial values • ANS: Initially MUTEX = 1,


of MUTEX and AVAIL? AVAIL = 0.

01/07/2022 Page 21
P/C problem: Bounded buffer
• Producer
Consumer
repeat
repeat
produce
while (in item v; NOP;
== out)
while((in+1)%n == out) NOP;
w = b[out];
b[in] = v;
out = (out + 1)%n;
in = ( in + 1)% n;
consume w;
forever;
forever;
• How to enforce bufsize?
• ANS: Using another counting semaphore.

01/07/2022 Page 22
P/C: Bounded Buffer solution
• Producer
repeat • Consumer
produce item v; repeat
BUFSIZE.wait(); AVAIL.wait();
MUTEX.wait(); MUTEX.wait();
b[in] = v; w = b[out];
in = (in + 1)%n; out = (out + 1)%n;
MUTEX.signal(); MUTEX.signal();
AVAIL.signal(); BUFSIZE.signal();
forever; consume w;
• What is the initial value of forever;
BUFSIZE? • ANS: size of the bounded
buffer.

01/07/2022 Page 23
Semaphores - comments
• Intuitively easy to use.
• wait() and signal() are to be implemented as atomic
operations.
• Difficulties:
– signal() and wait() may be exchanged inadvertently by the
programmer. This may result in deadlock or violation of
mutual exclusion.
– signal() and wait() may be left out.
• Related wait() and signal() may be scattered all over the code
among the processes.

01/07/2022 Page 24
Xinu Resources & Critical Resources
• Shared resources: need mutual exclusion
• Tasks cooperating to complete a job
• Tasks contending to access a resource
• Tasks synchronizing
• Critical resources and critical region
• A important synchronization and mutual
exclusion primitive / resource is “semaphore”

01/07/2022 Page 25
Critical sections and Semaphores
• When multiples tasks are executing there may be
sections where only one task could execute at a given
time: critical region or critical section
• There may be resources which can be accessed only
be one of the processes: critical resource
• Semaphores can be used to ensure mutual exclusion
to critical sections and critical resources

01/07/2022 Page 26
Semaphores
See semaphore.h of xinu

01/07/2022 Page 27
Semaphores in exinu
• #include <kernel.h>
• #include <queue.h> /**< queue.h must define # of sem queues */

• /* Semaphore state definitions */


• #define SFREE 0x01 /**< this semaphore is free */
• #define SUSED 0x02 /**< this semaphore is used */

• /* type definition of "semaphore" */


• typedef ulong semaphore;

• /* Semaphore table entry */


• struct sentry
• {
• char state; /**< the state SFREE or SUSED */
• short count; /**< count for this semaphore */
• queue queue; /**< requires q.h. */
• };

28
Semaphores in exinu (contd.)
• extern struct sentry semtab[];

• /**
• * isbadsem - check validity of reqested semaphore id and state
• * @param s id number to test; NSEM is declared to be 100 in kernel.h
• A system typically has a predetermined limited number of semaphores
• */
• #define isbadsem(s) (((ushort)(s) >= NSEM) || (SFREE == semtab[s].state))

• /* Semaphore function declarations */


• syscall wait(semaphore);
• syscall signal(semaphore);
• syscall signaln(semaphore, short);
• semaphore newsem(short);
• syscall freesem(semaphore);
• syscall scount(semaphore);

29
Definition of Semaphores functions
• static semaphore allocsem(void);
• /**
• * newsem - allocate and initialize a new semaphore.
• * @param count - number of resources available without waiting.
• * example: count = 1 for mutual exclusion lock
• * @return new semaphore id on success, SYSERR on failure
• */
• semaphore newsem(short count)
• {
• irqmask ps;
• semaphore sem;
• ps = disable(); /* disable interrupts */
• sem = allocsem(); /* request new semaphore */
• if ( sem != SYSERR && count >= 0 ) /* safety check */
• {
• semtab[sem].count = count; /* initialize count */
• restore(ps); /* restore interrupts */
• return sem; /* return semaphore id */
• }
• restore(ps);
• }

30
Semaphore: newsem contd.
• /**
• * allocsem - allocate an unused semaphore and return its index.
• * Scan the global semaphore table for a free entry, mark the entry
• * used, and return the new semaphore
• * @return available semaphore id on success, SYSERR on failure
• */
• static semaphore allocsem(void)
• {
• int i = 0;
• while(i < NSEM) /* loop through semaphore table */
• { /* to find SFREE semaphore */
• if( semtab[i].state == SFREE )
• {
• semtab[i].state = SUSED;
• return i;
• }
• i++;
• }
• return SYSERR; }

31
Semaphore: wait(…)
• /**
• * wait - make current process wait on a semaphore
• * @param sem semaphore for which to wait
• * @return OK on success, SYSERR on failure
• */
• syscall wait(semaphore sem)
•{
• irqmask ps;
• struct sentry *psem;
• pcb *ppcb;
• ps = disable(); /* disable interrupts */
• if ( isbadsem(sem) ) /* safety check */
• {
• restore(ps);
• return SYSERR;
• }
• ppcb = &proctab[currpid]; /* retrieve pcb from process table */
• psem = &semtab[sem]; /* retrieve semaphore entry */
• if( --(psem->count) < 0 ) /* if requested resource is unavailable */
• {
• ppcb->state = PRWAIT; /* set process state to PRWAIT*/

32
Semaphore: wait()
• ppcb->sem = sem; /* record semaphore id in pcb */
• enqueue(currpid, psem->queue);
• resched(); /* place in wait queue and reschedule */
• }
• restore(ps); /* restore interrupts */
• return OK;
• }

33
Semaphore: signal()
• /*signal - signal a semaphore, releasing one waiting process, and block
• * @param sem id of semaphore to signal
• * @return OK on success, SYSERR on failure
• */
• syscall signal(semaphore sem)
•{
• irqmask ps;
• register struct sentry *psem;

• ps = disable(); /* disable interrupts */


• if ( isbadsem(sem) ) /* safety check */
• {
• restore(ps);
• return SYSERR;
• }
• psem = &semtab[sem]; /* retrieve semaphore entry */
• if ( (psem->count++) < 0 ) /* release one process from wait queue */
• { ready(dequeue(psem->queue), RESCHED_YES); }
• restore(ps); /* restore interrupts */
• return OK;
•}

34
Semaphore: usage
• Problem 1:
– Create 3 tasks that each sleep for a random time and
update a counter.
– Counter is the critical resources shared among the
processes.
– Only one task can update the counter at a time so that
counter value is correct.
• Problem 2:
– Create 3 tasks; task 1 updates the counter by 1 and then
signal task 2 that updates the counter by 2 and then
signals task 3 to update the counter by 3.
35
Problem 1
#include <..>
//declare semaphore
semaphore mutex1 = newsem(1);
int counter = 0;
//declare functions: proc1,proc1, proc3
ready(create((void *)proc1, INITSTK, INITPRIO, “PROC1",, 2, 0,
NULL), RESCHED_NO);
ready(create((void *)proc2, INITSTK, INITPRIO, “PROC2",, 2, 0,
NULL), RESCHED_NO);
ready(create((void *)proc3, INITSTK, INITPRIO, “PROC3",, 2, 0,
NULL), RESCHED_NO);

36
Problem 1: multi-tasks
void proc1()
{ while (1) {
sleep (rand()%10);
wait(mutex1);
counter++;
signal(mutex1);
}}
void proc2()
{ while (1) {
sleep (rand()%10);
wait(mutex1);
counter++;
signal(mutex1);
}}
//similarly proc3

37
Problem 1

Task 1 Counter1 Task 2

Task 3

38
Problem 2
semaphore synch12 = newsem(0);
semaphore synch23 = newsem(0);
semaphore synch31 = newsem(0);
ready(create((void *)proc1, INITSTK, INITPRIO, “PROC1",, 2,
0, NULL), RESCHED_NO);
ready(create((void *)proc2, INITSTK, INITPRIO, “PROC2",, 2,
0, NULL), RESCHED_NO);
ready(create((void *)proc3, INITSTK, INITPRIO, “PROC3",, 2,
0, NULL), RESCHED_NO);
signal(synch31);
39
Task flow

void proc1() void proc2() void proc3()


•{ •{ •{
• while (1) { • while (1) { • while (1) {
• sleep (rand()%10); • sleep (rand()%10); • sleep(rand()%10);
• wait(synch31); • wait(synch12); • wait(synch23);
• counter++; • counter++; • counter++;
• signal(synch12); • signal(synch23); • signal(synch31); } }
•} } •} }

40

You might also like