Chapter 6: Process Synchronization - PowerPoint PPT Presentation

1 / 105
About This Presentation
Title:

Chapter 6: Process Synchronization

Description:

Either test memory word and set value. Or swap contents of two memory words. 6.11 ... Operating System Concepts. Using the TS Instruction. boolean s = FALSE; ... – PowerPoint PPT presentation

Number of Views:69
Avg rating:3.0/5.0
Slides: 106
Provided by: marilyntur
Category:

less

Transcript and Presenter's Notes

Title: Chapter 6: Process Synchronization


1
Chapter 6 Process Synchronization
2
Module 6 Process Synchronization
  • Background
  • The Critical-Section Problem
  • Petersons Solution
  • Synchronization Hardware
  • Semaphores
  • Classic Problems of Synchronization
  • Monitors
  • Synchronization Examples
  • Atomic Transactions


3
Background
  • Concurrent access to shared data may result in
    data inconsistency
  • Maintaining data consistency requires mechanisms
    to ensure the orderly execution of cooperating
    processes
  • Suppose that we wanted to provide a solution to
    the consumer-producer problem that fills all the
    buffers.
  • Use an integer count that keeps track of the
    number of full buffers.
  • Initially, count is set to 0.
  • It is incremented by the producer after it
    produces a new buffer and
  • is decremented by the consumer after it consumes
    a buffer.

4
Producer
  • while (true)
  • / produce an item
    and put in nextProduced
  • while (count BUFFER_SIZE)
  • // do nothing
  • buffer in nextProduced
  • in (in 1) BUFFER_SIZE
  • count

5
Consumer
  • while (1)
  • while (count 0)
  • // do nothing
  • nextConsumed bufferout
  • out (out 1) BUFFER_SIZE
  • count--
  • / consume the item in nextConsumed

6
Race Condition
  • count could be implemented as register1
    count register1 register1 1 count
    register1
  • count-- could be implemented as register2
    count register2 register2 - 1 count
    register2
  • Consider this execution interleaving with count
    5 initially
  • S0 producer execute register1 count
    register1 5S1 producer execute register1
    register1 1 register1 6 S2 consumer
    execute register2 count register2 5 S3
    consumer execute register2 register2 - 1
    register2 4 S4 producer execute count
    register1 count 6 S5 consumer execute
    count register2 count 4

7
Solution to Critical-Section Problem
  • 1. Mutual Exclusion - If process Pi is executing
    in its critical section, then no other processes
    can be executing in their critical sections
  • 2. Progress - If no process is executing in its
    critical section and there exist some processes
    that wish to enter their critical section, then
    the selection of the processes that will enter
    the critical section next cannot be postponed
    indefinitely
  • 3. Bounded Waiting - A bound must exist on the
    number of times that other processes are allowed
    to enter their critical sections after a process
    has made a request to enter its critical section
    and before that request is granted
  • Assume that each process executes at a nonzero
    speed
  • No assumption concerning relative speed of the N
    processes

8
Petersons Solution
  • Two process solution
  • Assume that the LOAD and STORE instructions are
    atomic that is, cannot be interrupted.
  • The two processes share two variables
  • int turn
  • Boolean flag2
  • The variable turn indicates whose turn it is to
    enter the critical section.
  • The flag array is used to indicate if a process
    is ready to enter the critical section. flagi
    true implies that process Pi is ready!

9
Algorithm for Process Pi
  • do
  • flagi TRUE
  • turn j
  • while ( flagj turn j)
  • CRITICAL SECTION
  • flagi FALSE
  • REMAINDER SECTION
  • while (TRUE)

10
Synchronization Hardware
  • Many systems provide hardware support for
    critical section code
  • Uniprocessors could disable interrupts
  • Currently running code would execute without
    preemption
  • Generally too inefficient on multiprocessor
    systems
  • Operating systems using this not broadly scalable
  • Modern machines provide special atomic hardware
    instructions
  • Atomic non-interruptable
  • Either test memory word and set value
  • Or swap contents of two memory words

11
TestAndndSet Instruction
  • Definition
  • boolean TestAndSet (boolean target)
  • boolean rv target
  • target TRUE
  • return rv

12
Implementing SemaphoresTest and Set Instruction
  • TS R3, m test-and-set of location m
  • TS(m) Reg_i memorym memorym TRUE CC
    value(Reg_i)

Data Register
ConditionCode Register
R3


m
FALSE
Primary Memory
  • Before Executing TS

13
Solution using TestAndSet
  • Shared boolean variable lock., initialized to
    false.
  • Solution
  • do
  • while ( TestAndSet (lock ))
  • / do nothing
  • // critical section
  • lock FALSE
  • // remainder section
  • while ( TRUE)

14
Swap Instruction
  • Definition
  • void Swap (boolean a, boolean b)
  • boolean temp a
  • a b
  • b temp

15
Solution using Swap
  • Shared Boolean variable lock initialized to
    FALSE Each process has a local Boolean variable
    key.
  • Solution
  • do
  • key TRUE
  • while ( key TRUE)
  • Swap (lock, key )
  • // critical section
  • lock FALSE
  • // remainder section
  • while ( TRUE)

16
Semaphore
  • Synchronization tool that does not require busy
    waiting
  • Implemented by the OS
  • Implemented without busy waiting
  • Semaphore S integer variable
  • Two standard operations modify S wait() and
    signal()
  • Originally called P() and V()
  • P(s) proberen, to test
  • V(s) verhogen, to increment or signal
  • Less complicated

17
Semaphore Implementation with no Busy waiting
(Cont.)
  • Implementation of wait with no busy waiting
  • wait (S)
  • value--
  • if (value lt 0)
  • add this process to waiting
    queue
  • block()
  • Implementation of signal
  • Signal (S)
  • value
  • if (value lt 0)
  • remove a process P from the
    waiting queue
  • wakeup(P)

18
Semaphore as General Synchronization Tool
  • 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
  • Also known as mutex locks
  • Can implement a counting semaphore S as a binary
    semaphore

19
Using the TS Instruction
Solution using TS
Solution using semaphores
boolean s FALSE . . . while(TS(s))
ltcritical sectiongt s FALSE . . .
semaphore s 1 . . . wait(s) ltcritical
sectiongt signal(s) . . .
The first process finds s to be FALSE. All
remaining process find s to be TRUE until the
first process executes s FALSE
20
Using the TS Instruction
  • The TS instruction can be used to implement the
    binary semaphore.
  • Can it be used for the general semaphore?

21
Semaphore Implementation
  • Must guarantee that no two processes can execute
    wait () and signal () on the same semaphore at
    the same time
  • Thus, implementation becomes the critical section
    problem where the wait and signal code are placed
    in the critical section.
  • Could now have busy waiting in critical section
    implementation
  • But implementation code is short
  • Little busy waiting if critical section rarely
    occupied
  • Note that applications may spend lots of time in
    critical sections and therefore this is not a
    good solution.

22
Semaphore Implementation with no Busy waiting
  • With each semaphore there is an associated
    waiting queue. Each entry in a waiting queue has
    two data items
  • value (of type integer)
  • pointer to next record in the list
  • Two operations
  • block place the process invoking the operation
    on the appropriate waiting queue.
  • wakeup remove one of processes in the waiting
    queue and place it in the ready queue.

23
Implementing the General Semaphore
struct semaphore int value ltinitial
valuegt boolean mutex FALSE boolean hold
TRUE shared struct semaphore s wait(struct
semaphore s) while(TS(s.mutex))
s.value-- if(s.value lt 0) ( s.mutex
FALSE while(TS(s.hold)) else
s.mutex FALSE
Variable mutex ensures mutual exclusion in the CS.
This while statement is necessary to prevent
a race . The signaling process loops
until another process does a P operation.
signal(struct semaphore s) while(TS(s.mutex))
s.value if(s.value lt 0) (
while(!s.hold) s.hold FALSE
s.mutex FALSE
When a process signals, the value is incremented.
Variable hold causes processes to busy-wait if
the semaphore is less than 0.
24
Implementing the General Semaphore
Solution without busy-waiting
struct semaphore int value ltinitial
valuegt boolean mutex FALSE boolean hold
TRUE shared struct semaphore s wait(struct
semaphore s) while(TS(s.mutex)) yield (,
scheduler) s.value-- if(s.value lt 0) (
s.mutex FALSE while(TS(s.hold)) yield (,
scheduler) else s.mutex FALSE
When a process must wait, it yields the CPU. Uses
the yield instruction from chapter 7.
signal(struct semaphore s) while(TS(s.mutex))
yield (, scheduler) s.value
if(s.value lt 0) ( while(!s.hold) yield (,
scheduler) s.hold FALSE s.mutex
FALSE
25
Active vs Passive Semaphores
  • A process can dominate the semaphore
  • Performs signal operation, but continues to
    execute
  • Performs another wait operation before releasing
    the CPU
  • Called a passive implementation of V
  • Active implementation calls scheduler as part of
    the V operation.
  • Changes semantics of semaphore!
  • Cause people to rethink solutions

26
Deadlock and Starvation
  • Deadlock two or more processes are waiting
    indefinitely for an event that can be caused by
    only one of the waiting processes
  • Let S and Q be two semaphores initialized to 1
  • P0 P1
  • wait (S)
    wait (Q)
  • wait (Q)
    wait (S)
  • . .
  • . .
  • . .
  • signal (S)
    signal (Q)
  • signal (Q)
    signal (S)
  • Starvation indefinite blocking. A process may
    never be removed from the semaphore queue in
    which it is suspended.

27
Classical Problems of Synchronization
  • Bounded-Buffer Problem
  • Readers and Writers Problem
  • Dining-Philosophers Problem

28
Bounded Buffer Problem
Empty Pool
Producer
Consumer
Full Pool
29
Bounded-Buffer Problem
  • use counting semaphores
  • they keep a count of the number of empty and full
    buffers
  • also synchronize the producer/consumer
  • empty semaphore used to block producer if no
    empty buffers left
  • initialized to the value N.
  • full semaphore used to block consumer if no full
    buffers left
  • initialized to the value 0
  • mutex semaphore protects CS where buffers are
    manipulated N buffers, each can hold one item
  • initialized to the value 1

30
Bounded Buffer Problem (Cont.)
  • The structure of the producer process
  • do
  • // produce an item
  • wait (empty)
  • wait (mutex)
  • // add the item to the
    buffer
  • signal (mutex)
  • signal (full)
  • while (true)

31
Bounded Buffer Problem (Cont.)
  • The structure of the consumer process
  • do
  • wait (full)
  • wait (mutex)
  • // remove an item from
    buffer
  • signal (mutex)
  • signal (empty)
  • // consume the removed item
  • while (true)

32
Bounded Buffer Problem (Unix)
producer() buf_type next, here
while(TRUE) produce_item(next) / Claim
an empty / P(empty) P(mutex)
here obtain(empty) V(mutex)
copy_buffer(next, here) P(mutex)
release(here, fullPool) V(mutex) /
Signal a full buffer / V(full)
semaphore mutex 1 semaphore full 0
/ A general (counting) semaphore / semaphore
empty N / A general (counting) semaphore
/ buf_type bufferN fork(producer,
0) fork(consumer, 0)
consumer() buf_type next, here
while(TRUE) / Claim full buffer /
P(mutex) P(full) here
obtain(full) V(mutex) copy_buffer(here,
next) P(mutex) release(here,
emptyPool) V(mutex) / Signal an empty
buffer / V(empty) consume_item(next)

33
Bounded Buffer Problem (Unix)
producer() buf_type next, here
while(TRUE) produce_item(next) / Claim
an empty / P(empty) P(mutex)
here obtain(empty) V(mutex)
copy_buffer(next, here) P(mutex)
release(here, fullPool) V(mutex) /
Signal a full buffer / V(full)
semaphore mutex 1 semaphore full 0
/ A general (counting) semaphore / semaphore
empty N / A general (counting) semaphore
/ buf_type bufferN fork(producer,
0) fork(consumer, 0)
consumer() buf_type next, here
while(TRUE) / Claim full buffer /
P(full) P(mutex) here
obtain(full) V(mutex) copy_buffer(here,
next) P(mutex) release(here,
emptyPool) V(mutex) / Signal an empty
buffer / V(empty) consume_item(next)

34
Readers-Writers Problem
  • A data set is shared among a number of concurrent
    processes
  • Readers only read the data set they do not
    perform any updates
  • Writers can both read and write.
  • Problem allow multiple readers to read at the
    same time. Only one single writer can access the
    shared data at the same time.
  • Shared Data
  • Data set
  • Semaphore mutex initialized to 1.
  • Semaphore wrt initialized to 1.
  • Integer readcount initialized to 0.

35
Readers-Writers Problem (Cont.)
  • The structure of a writer process
  • do
  • wait (wrt)
  • // writing is performed
  • signal (wrt)
  • while (true)

36
Readers-Writers Problem (Cont.)
  • The structure of a reader process
  • do
  • wait (mutex)
  • readcount
  • if (readercount 1) wait
    (wrt)
  • signal (mutex)
  • // reading is
    performed
  • wait (mutex)
  • readcount - -
  • if redacount 0) signal
    (wrt)
  • signal (mutex)
  • while (true)

37
First Unix Solution
reader() while(TRUE) ltother
computinggt P(mutex) readCount
if(readCount 1) P(writeBlock)
V(mutex) / Critical section /
access(resource) P(mutex)
readCount-- if(readCount 0)
V(writeBlock) V(mutex) resourceType
resource int readCount 0 semaphore mutex
1 semaphore writeBlock 1 fork(reader,
0) fork(writer, 0)
writer() while(TRUE) ltother
computinggt P(writeBlock) / Critical
section / access(resource)
V(writeBlock)
38
First Solution (2)
reader() while(TRUE) ltother
computinggt P(mutex) readCount
if(readCount 1) P(writeBlock)
V(mutex) / Critical section /
access(resource) P(mutex)
readCount-- if(readCount 0)
V(writeBlock) V(mutex) resourceType
resource int readCount 0 semaphore mutex
1 semaphore writeBlock 1 fork(reader,
0) fork(writer, 0)
writer() while(TRUE) ltother
computinggt P(writeBlock) / Critical
section / access(resource)
V(writeBlock)
  • First reader competes with writers
  • Last reader signals writers
  • Any writer must wait for all readers
  • Readers can starve writers
  • Updates can be delayed forever
  • May not be what we want

39
Writer Precedence (Unix)
reader() while(TRUE) ltother
computinggt P(readBlock)
P(mutex1) readCount
if(readCount 1) P(writeBlock)
V(mutex1) V(readBlock)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
First Writer does a P(readBlock) to block any new
readers
40
Writer Precedence (in Unix)
reader() while(TRUE) ltother
computinggt P(readBlock)
P(mutex1) readCount
if(readCount 1) P(writeBlock)
V(mutex1) V(readBlock)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
Next reader is blocked because the first
writer did a P(readBlock)
Writer blocks on P(writeBlock)
41
Writer Precedence (in Unix)
reader() while(TRUE) ltother
computinggt P(readBlock)
P(mutex1) readCount
if(readCount 1) P(writeBlock)
V(mutex1) V(readBlock)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
42
Writer Precedence (2)
reader() while(TRUE) ltother
computinggt P(writePending)
P(readBlock) P(mutex1)
readCount if(readCount 1)
P(writeBlock) V(mutex1)
V(readBlock) V(writePending)
access(resource) P(mutex1)
readCount-- if(readCount 0)
V(writeBlock) V(mutex1) int readCount
0, writeCount 0 semaphore mutex 1, mutex2
1 semaphore readBlock 1, writeBlock 1,
writePending 1 fork(reader, 0) fork(writer,
0)
writer() while(TRUE) ltother
computinggt P(mutex2) writeCount
if(writeCount 1) P(readBlock)
V(mutex2) P(writeBlock)
access(resource) V(writeBlock)
P(mutex2) writeCount-- if(writeCount
0) V(readBlock) V(mutex2)
Any new reader must wait until the last
writer signals
Any new writer has priority over any waiting
reader but is stuck until first writer is
finished
43
Writer Precedence (2)
  • Any writer must wait for current readers to
    finish
  • Any writer has priority over any new readers
  • The writers can starve readers
  • Reads can be delayed forever
  • May not be what we want

44
Dining-Philosophers Problem
  • Shared data
  • Bowl of rice (data set)
  • Semaphore chopstick 5 initialized to 1

45
Dining-Philosophers Problem (Cont.)
  • The structure of Philosopher i
  • Do
  • wait ( chopsticki )
  • wait ( chopStick (i 1) 5 )
  • // eat
  • signal ( chopsticki )
  • signal (chopstick (i 1) 5 )
  • // think
  • while (true)

Deadlock! Where? Will see a solution in monitors
later.
46
Problems with Semaphores
  • Incorrect use of semaphore operations
  • signal (mutex) . wait (mutex)
  • wait (mutex) wait (mutex)
  • Omitting of wait (mutex) or signal (mutex) (or
    both)

47
Monitors
  • An attempt to provide better tools for
    synchronization problems
  • Specialized form of ADT
  • Encapsulates implementation
  • Public interface (types functions)
  • Only one process can be executing in the ADT at a
    time
  • other processes that try to use the monitor are
    forced to wait

monitor anADT semaphore mutex 1 //
Implicit . . . public proc_i()
P(mutex) // Implicit ltprocessing for
proc_igt V(mutex) // Implicit . .
.
Conceptually how monitors are implemented. Actual
implementations vary
48
Monitors
  • Only one process may be active within the monitor
    at a time
  • monitor monitor-name
  • // shared variable declarations
  • procedure P1 () .
  • procedure Pn ()
  • Initialization code ( .)

49
Schematic view of a Monitor
50
Example1 Shared Balance
programmer does not have to use semaphores only
one process can be in any function of the monitor
at a time. Implicit semaphores are added by the
compiler.
monitor sharedBalance double
balance public credit(double amount) balance
amount debit(double amount) balance -
amount . . . In process 1
code sharedBalance.credit(100) In process 2
code sharedBalance.debit(50)
51
Example2 Readers Writers
Solution outline
monitor readerWriter_1 int numberOfReaders
0 int numberOfWriters 0 boolean busy
FALSE public startRead()
finishRead() startWrite()
finishWrite()
reader() while(TRUE) . . .
startRead() finishRead() . .
. fork(reader, 0) . . . fork(reader,
0) fork(writer, 0) . . . fork(writer, 0)
writer() while(TRUE) . . .
startWrite() finishWrite() . . .
52
Example Readers Writers
monitor readerWriter_1 int numberOfReaders
0 int numberOfWriters 0 boolean busy
FALSE public startRead()
while(numberOfWriters ! 0)
numberOfReaders finishRead()
numberOfReaders--
startWrite() numberOfWriters
while( busy
(numberOfReaders gt 0) ) busy
TRUE finishWrite()
numberOfWriters-- busy FALSE
53
Example Readers Writers
monitor readerWriter_1 int numberOfReaders
0 int numberOfWriters 0 boolean busy
FALSE public startRead()
while(numberOfWriters ! 0)
numberOfReaders finishRead()
numberOfReaders--
startWrite() numberOfWriters
while( busy
(numberOfReaders gt 0) ) busy
TRUE finishWrite()
numberOfWriters-- busy FALSE
54
Sometimes Need to Suspend
  • Process obtains monitor, but detects a condition
    for which it needs to wait
  • Want special mechanism to suspend until condition
    is met, then resume
  • Process that makes condition true must exit
    monitor
  • Suspended process then resumes
  • Condition Variable

55
Monitor with Condition Variables
56
Condition Variables
  • Essentially an event (as defined previously)
  • Occurs only inside a monitor
  • Operations to manipulate condition variable
  • wait Suspend invoking process until another
    executes a signal
  • signal Resume one process if any are suspended,
    otherwise do nothing
  • queue Return TRUE if there is at least one
    process suspended on the condition variable
  • Example
  • condition x, y
  • x.wait ()
  • x.signal ()

57
Condition Variables
  • Two ways to implement condition variables
  • Hoares semantics
  • p1 does a wait
  • p0 signals
  • p0 is immediately suspended, p1 is immediately
    resumed
  • when p1 finishes and leaves the monitor, p0
    continues

58
Condition Variables
  • Two ways to implement condition variables
  • Brinch Hansens semantics
  • p1 does a wait
  • p0 signals
  • p0 finishes and leaves the monitor
  • when p0 leaves the monitor, p1 checks to see if
    its condition still holds. If it does, p1
    continues in the monitor.

59
Active vs Passive signal
  • Hoare semantics same as active semaphore
  • p0 executes signal while p1 is waiting ? p0
    yields the monitor to p1
  • The signal is only TRUE the instant it happens
  • Brinch Hansen (Mesa) semantics same as passive
    semaphore
  • p0 executes signal while p1 is waiting ? p0
    continues to execute, then when p0 exits the
    monitor p1 can receive the signal
  • Used in the Xerox Mesa implementation

60
Hoare vs Mesa Semantics
condition variable
  • Hoare semantics
  • Use if to check if resource is available.

. . . if(resourceNotAvailable())
resourceCondition.wait() / now available
continue / . . .
  • Mesa semantics
  • Must loop because must check to see if resource
    is still available when we finally get the signal

. . . while(resourceNotAvailable())
resourceCondition.wait() / now available
continue / . . .
61
2nd Try at Readers Writers
monitor readerWriter_2 int numberOfReaders
0 boolean busy FALSE condition okToRead,
okToWrite public startRead() if(busy
(okToWrite.queue()) okToRead.wait()
numberOfReaders okToRead.signal()
finishRead() numberOfReaders--
if(numberOfReaders 0) okToWrite.signal()

startWrite() if((numberOfReaders ! 0)
busy) okToWrite.wait() busy
TRUE finishWrite() busy FALSE
if(okToRead.queue()) okToRead.signal()
else okToWrite.signal()
62
Example Synchronizing Traffic
  • One-way tunnel
  • Can only use tunnel if no oncoming traffic
  • OK to use tunnel if traffic is already flowing
    the right way
  • In class
  • Problem 1 make the synchronization work (dont
    worry about fairness)
  • Problem 2 add fairness

63
Example Synchronizing Traffic
monitor tunnel int northbound 0, southbound
0 trafficSignal nbSignal RED, sbSignal
GREEN condition busy public nbArrival()
if(southbound gt 0) busy.wait()
northbound nbSignal GREEN sbSignal
RED sbArrival() if(northbound gt 0)
busy.wait() southbound nbSignal
RED sbSignal GREEN depart(Direction
exit) ( if(exit NORTH
northbound-- if(northbound 0)
while(busy.queue()) busy.signal() else
if(exit SOUTH) southbound--
if(southbound 0) while(busy.queue())
busy.signal()
64
Dining Philosophers again ...
  • Use an array state to indicate state of the
    philosophers
  • statei thinking when philosopher i is
    thinking
  • When philosopher i wishes to eat, calls the
    monitor function pickUpForks(i)
  • only allowed to pick up a fork if both adjacent
    forks are available
  • use the private function test( )
  • philosopher moves to eating state only if two
    neighbors are not in eating state.
  • otherwise waits for a signal
  • both philosophers on either side have to call
    putDownForks( ) before philosopher can move from
    hungry to eating state.

65
Dining Philosophers again ...
define N ___ enum status(EATING, HUNGRY,
THINKING monitor diningPhilosophers status
stateN condition selfN test(int i)
if((state(i-1) mod N ! EATING)
(statei HUNGRY) (state(i1) mod
N ! EATING)) statei EATING
selfi.signal() public
diningPhilosophers() // Initilization
for(int i 0 i lt N i) statei THINKING

66
Dining Philosophers again ...
test(int i) if((state(i-1) mod N !
EATING) (statei HUNGRY)
(state(i1) mod N ! EATING)) statei
EATING selfi.signal()
public diningPhilosophers() ...
pickUpForks(int i) statei HUNGRY
test(i) if(statei ! EATING)
selfi.wait() putDownForks(int i)
statei THINKING test((i-1) mod N)
test((i1) mod N)
67
Experience with Monitors
  • Danger of deadlock with nested calls
  • call another monitor from within a monitor
  • example try to call a function in monitor B from
    within a function in monitor A
  • but what if some other process is currently in
    monitor A and wants into monitor B?
  • same problem as with nested semaphores

68
Experience with Monitors
  • Implementation of monitors
  • not in UNIX (some versions support similar
    mechanisms)
  • some languages support (Modula-3 and Java)
  • Monitors were implemented in Xeroxs Mesa
    programming language
  • Used Brinch Hansen semantics
  • Nested monitor calls are, in fact, a problem
  • which wait implementation is best?
  • how is priority scheduling done?
  • Needed timeouts, aborts, etc.
  • See paper by Lampson Redell

69
Atomic Transactions
  • Sometimes would like to make sure that a critical
    section forms a single logical unit of work
  • Either is performed in entirety or not at all
  • Consistency of data is a concern associated with
    database systems
  • Recent trend store all user information in OS
    database
  • Makes retrieval and search fast and effective
  • Many OS are trying to implement this OS X,
    Vista, etc.
  • Thus it is useful to consider DB techniques used
    to assure atomicity.
  • We wont go there. See your book, section 6.9

70
Synchronization Examples
  • Solaris
  • Windows XP
  • Linux
  • Pthreads

71
Solaris Synchronization
  • Implements a variety of locks to support
    multitasking, multithreading (including real-time
    threads), and multiprocessing
  • Uses adaptive mutexes for efficiency when
    protecting data from short code segments
  • Uses condition variables and readers-writers
    locks when longer sections of code need access to
    data
  • Uses turnstiles to order the list of threads
    waiting to acquire either an adaptive mutex or
    reader-writer lock

72
Windows XP Synchronization
  • Uses interrupt masks to protect access to global
    resources on uniprocessor systems
  • Uses spinlocks on multiprocessor systems
  • Also provides dispatcher objects which may act as
    either mutexes and semaphores
  • Dispatcher objects may also provide events
  • An event acts much like a condition variable

73
Linux Synchronization
  • Linux
  • disables interrupts to implement short critical
    sections
  • Linux provides
  • semaphores
  • spin locks

74
Semaphores in Linux
  • Interprocess communication facilities were
    introduced in the ATT System V.2 release of
    UNIX.
  • These facilities have a similar programming
    interface and are thus referred to as the IPC
    facilities or System V IPC.
  • There are now other ways of communicating between
    processes (eg, pipes).
  • The three System V IPC mechanisms
  • Semaphores
  • Message Queues
  • Shared Memory
  • Well only talk about semaphores here.

75
Semaphores in Linux
  • The LINUX semaphore interface is elaborate.
  • offers far more facilities than are generally
    required
  • All UNIX semaphore functions operate on arrays of
    general semaphores.

76
Semaphores in Linux
  • Semaphore functions
  • include ltsys/sem.hgt
  • int semctl(int sem_id, int sem_num, int command,
    )
  • int semget(key_t key, int num_sems, int
    sem_flags)
  • int semop(int sem_id, struct sembuf sem_ops,
    size_t num_sem_ops)

77
Semaphores in Linux
  • useful include files
  • include ltunistd.hgt
  • include ltsys/types.hgt
  • include ltsys/ipc.hgt
  • include ltsys/sem.hgt

78
Semaphores in Linux
  • We do not need such powerful semaphores.
  • Will use an abstraction that creates general
    semaphores from the Linux semaphore facilities.
  • You can find details about the Linux semaphore
    facilities in the Beginning Linux Programming
    book.

79
Semaphores in Linux
  • The functions available in our abstraction
  • static int start_semvalue(int sem_num)
  • creates a semaphore and returns a semaphore ID.
    Different processes can access the same semaphore
    by using the same sem_num.
  • static int set_semvalue(int sem_id,int semVal)
  • sets the value of semaphore sem_id to be semVal.

80
Semaphores in Linux
  • The functions available in our abstraction
  • static void del_semvalue(int sem_id)
  • removes a semaphore identifier. Does not delete
    the semaphore other processes can still use it.
  • static int semaphore_p(int sem_id)
  • does a P operation on sem_id.
  • static int semaphore_v(int sem_id)
  • does a V operation on sem_id.

81
Semaphores in LinuxbinSem.h
  • static int start_semvalue(int sem_num)
  • return( semget((key_t)sem_num, 1, 0666
    IPC_CREAT))

82
Semaphores in LinuxbinSem.h
  • static int set_semvalue(int sem_id,int semVal)
  • union semun
  • int val
  • struct semid_ds buf
  • ushort array
  • sem_union
  • sem_union.val semVal
  • if (semctl(sem_id, 0, SETVAL,sem_union)
    -1) return(0)
  • return(1)

83
Semaphores in LinuxbinSem.h
  • static void del_semvalue(int sem_id)
  • union semun
  • int val
  • struct semid_ds buf
  • ushort array
  • sem_union
  • if (semctl(sem_id, 0, IPC_RMID, sem_union)
    -1)
  • fprintf(stderr, "Failed to delete semaphore
    \n")

84
Semaphores in LinuxbinSem.h
  • static int semaphore_p(int sem_id)
  • struct sembuf sem_b
  • sem_b.sem_num 0
  • sem_b.sem_op -1 / P() /
  • sem_b.sem_flg SEM_UNDO
  • if (semop(sem_id, sem_b, 1) -1)
  • fprintf(stderr, "semaphore_p failed\n")
  • return(0)
  • return(1)

85
Semaphores in LinuxbinSem.h
  • static int semaphore_v(int sem_id)
  • struct sembuf sem_b
  • sem_b.sem_num 0
  • sem_b.sem_op 1 / V() /
  • sem_b.sem_flg SEM_UNDO
  • if (semop(sem_id, sem_b, 1) -1)
  • fprintf(stderr, "semaphore_v failed\n")
  • return(0)
  • return(1)

86
Semaphores in Linuxexample
  • include ltstdlib.hgt
  • include ltstdio.hgt
  • include ltsys/types.hgt
  • include ltsys/ipc.hgt
  • include ltsys/sem.hgt
  • include "binSem.h"
  • static int sem_id

87
Semaphores in Linuxexample
  • int main(int argc, char argv)
  • int i
  • int pause_time
  • char op_char 'O'
  • srand((unsigned int)getpid())
  • sem_id start_semvalue(1234)
  • if (argc gt 1)
  • if (!set_semvalue(sem_id,1))
  • fprintf(stderr, "Failed to initialize
    semaphore\n")
  • exit(EXIT_FAILURE)
  • op_char 'X'
  • sleep(2)

To run this program, execute it once in
the background with a command line parameter,
then execute it again with no parameter. gtgcc
ex1.c gt a.out 1 1 1082 gt a.out 00XX00XX00XX000
0 1083 finished 1082 finished gt
output will be even numbers of Xs interspersed
with even numbers of 0s
88
Semaphores in Linuxexample
  • for(i 0 i lt 10 i)
  • if (!semaphore_p(sem_id))
    exit(EXIT_FAILURE)
  • / start of critical section /
  • printf("c", op_char)fflush(stdout)
  • pause_time rand() 3
  • sleep(pause_time)
  • printf("c", op_char)fflush(stdout)
  • / end of critical section /
  • if (!semaphore_v(sem_id))
    exit(EXIT_FAILURE)
  • pause_time rand() 2
  • sleep(pause_time)

89
Semaphores in Linuxexample
  • printf("\nd - finished\n", getpid())
  • if (argc gt 1)
  • sleep(10)
  • del_semvalue(sem_id)
  • exit(EXIT_SUCCESS)

90
Semaphores in Linuxexample 2
  • In this example, a child is forked off.
  • The parent creates and initializes the semaphore
    before creating the child.
  • The child and parent each have a CS.
  • both open the same file in their CS.
  • The parent writes two Ps into the file
  • The child writes two Cs into the file
  • Each CS is inside a loop. Both parent and child
    loop 10 times.

91
Semaphores in Linuxexample 2
  • include "binSem.h"
  • static int sem_id
  • int main(int argc, char argv)
  • int i
  • int pause_time
  • char op_char 'C'
  • FILE fd
  • char name"temp2.txt"
  • srand((unsigned int)getpid())
  • sem_id start_semvalue(1234)
  • if (!set_semvalue(sem_id,1) )
  • fprintf(stderr, "Failed to initialize
    semaphore\n")
  • exit(EXIT_FAILURE)

92
Semaphores in Linuxexample 2
The child code
  • if (fork() 0)
  • for(i 0 i lt 10 i)
  • if (!semaphore_p(sem_id))
    exit(EXIT_FAILURE)
  • / start of critical section /
  • fd fopen(name, "a")
  • fprintf(fd, "c", op_char)fflush(stdout
    )
  • pause_time rand() 3
  • sleep(pause_time)
  • fprintf(fd, "c", op_char)fflush(stdout
    )
  • fclose(fd)
  • / end of critical section /
  • if (!semaphore_v(sem_id))
    exit(EXIT_FAILURE)
  • pause_time rand() 2
  • sleep(pause_time)
  • exit(0)

93
Semaphores in Linuxexample 2
The parent code
  • / we're in the parent's code /
  • op_char 'P'
  • for(i 0 i lt 10 i)
  • if (!semaphore_p(sem_id))
    exit(EXIT_FAILURE)
  • / start of critical section /
  • fd fopen(name, "a")
  • fprintf(fd, "c", op_char)fflush(stdout
    )
  • pause_time rand() 3
  • sleep(pause_time)
  • fprintf(fd, "c", op_char)fflush(stdout
    )
  • fclose(fd)
  • / end of critical section /
  • if (!semaphore_v(sem_id))
    exit(EXIT_FAILURE)
  • pause_time rand() 2
  • sleep(pause_time)

94
Semaphores in Linuxexample 2
  • wait(NULL)
  • printf("\nd - finished\n", getpid())
  • del_semvalue(sem_id)
  • exit(EXIT_SUCCESS)

95
Pthreads Synchronization
  • Pthreads API is OS-independent
  • It provides
  • mutex locks
  • condition variables
  • Non-portable extensions include
  • read-write locks
  • spin locks

96
Pthreads Synchronization
  • Semaphores in pthreads
  • Semaphore functions start with sem_
  • Must include the library
  • include ltsemaphore.hgt
  • initializing (for binary semaphores)
  • int sem_init(sem_t sem, int pshared, unsigned
    int value)
  • sem is the semaphore
  • pshared is the type of semaphore
  • if 0, then semaphore is local to the current
    process
  • O.W. the semaphore may be shared between processes

97
Pthreads Synchronization
  • initializing (for binary semaphores)
  • int sem_wait(sem_t sem)
  • int sem_post(sem_t sem)
  • sem is thepointer to a semaphore object

98
Pthreads Semaphores Example
  • include ltstdio.hgt
  • include ltunistd.hgt
  • include ltstdlib.hgt
  • include ltpthread.hgt
  • include ltsemaphore.hgt
  • void thread_function(void arg)
  • sem_t bin_sem
  • define WORK_SIZE 1024
  • char work_areaWORK_SIZE
  • int main()
  • int res
  • pthread_t a_thread
  • void thread_result

99
Pthreads Semaphores Example
  • res sem_init(bin_sem, 0, 0)
  • if (res ! 0)
  • perror("Semaphore initialization
    failed")
  • exit(EXIT_FAILURE)
  • res pthread_create(a_thread, NULL,
    thread_function, NULL)
  • if (res ! 0)
  • perror("Thread creation failed")
  • exit(EXIT_FAILURE)
  • printf("Input some text. Enter 'end' to
    finish\n")
  • while(strncmp("end", work_area, 3) ! 0)
  • fgets(work_area, WORK_SIZE, stdin)
  • sem_post(bin_sem)
  • printf("\nWaiting for thread to
    finish...\n")
  • res pthread_join(a_thread, thread_result)
  • if (res ! 0)
  • perror("Thread join failed")

100
Pthreads Semaphores Example
  • printf("Thread joined\n")
  • sem_destroy(bin_sem)
  • exit(EXIT_SUCCESS)
  • void thread_function(void arg)
  • sem_wait(bin_sem)
  • while(strncmp("end", work_area, 3) ! 0)
  • printf("You input d characters\n",
    strlen(work_area) -1)
  • sem_wait(bin_sem)
  • pthread_exit(NULL)

101
Pthreads Mutex Example
  • include ltstdio.hgt
  • include ltunistd.hgt
  • include ltstdlib.hgt
  • include ltpthread.hgt
  • include ltsemaphore.hgt
  • void thread_function(void arg)
  • pthread_mutex_t work_mutex / protects both
    work_area and time_to_exit /
  • define WORK_SIZE 1024
  • char work_areaWORK_SIZE
  • int time_to_exit 0

102
Pthreads Mutex Example
  • int main()
  • int res
  • pthread_t a_thread
  • void thread_result
  • res pthread_mutex_init(work_mutex, NULL)
  • if (res ! 0)
  • perror("Mutex initialization failed")
  • exit(EXIT_FAILURE)
  • res pthread_create(a_thread, NULL,
    thread_function, NULL)
  • if (res ! 0)
  • perror("Thread creation failed")
  • exit(EXIT_FAILURE)
  • pthread_mutex_lock(work_mutex)
  • printf("Input some text. Enter 'end' to
    finish\n")

103
Pthreads Mutex Example
  • while(!time_to_exit)
  • fgets(work_area, WORK_SIZE, stdin)
  • pthread_mutex_unlock(work_mutex)
  • while(1)
  • pthread_mutex_lock(work_mutex)
  • if (work_area0 ! '\0')
  • pthread_mutex_unlock(work_mutex)
  • sleep(1)
  • else
  • break
  • pthread_mutex_unlock(work_mutex)
  • printf("\nWaiting for thread to
    finish...\n")
  • res pthread_join(a_thread, thread_result)
  • if (res ! 0)
  • perror("Thread join failed")

104
Pthreads Mutex Example
  • void thread_function(void arg)
  • sleep(1)
  • pthread_mutex_lock(work_mutex)
  • while(strncmp("end", work_area, 3) ! 0)
  • printf("You input d characters\n",
    strlen(work_area) -1)
  • work_area0 '\0'
  • pthread_mutex_unlock(work_mutex)
  • sleep(1)
  • pthread_mutex_lock(work_mutex)
  • while (work_area0 '\0' )
  • pthread_mutex_unlock(work_mutex)
  • sleep(1)
  • pthread_mutex_lock(work_mutex)
  • time_to_exit 1
  • work_area0 '\0'
  • pthread_mutex_unlock(work_mutex)
  • pthread_exit(0)

105
End of Chapter 6
Write a Comment
User Comments (0)
About PowerShow.com