Inter Process Synchronization and Communication - PowerPoint PPT Presentation

About This Presentation
Title:

Inter Process Synchronization and Communication

Description:

Inter Process Synchronization and Communication CT213 Computing Systems Organization * Note that this problem is a particularization of the producer/consumer ... – PowerPoint PPT presentation

Number of Views:337
Avg rating:3.0/5.0
Slides: 77
Provided by: ww2ItNuig3
Category:

less

Transcript and Presenter's Notes

Title: Inter Process Synchronization and Communication


1
Inter Process Synchronization and Communication
  • CT213 Computing Systems Organization

2
Content
  • Parallel computation
  • Process interaction
  • Processes unaware of each other
  • Processes indirectly aware of each other
  • Processes directly aware of each other
  • Critical sections
  • Mutual exclusion
  • Software approaches (Dekker Algorithm, Petersons
    Algorithm)
  • Hardware approaches (Interrupt disabling, ISA
    modification)
  • Semaphores mutual exclusion with semaphores
  • Producer Consumer problems
  • Semaphores implementation
  • Messages design issues
  • Readers/Writers problem

3
Parallel Computation
  • Is made up from multiple, independent parts that
    are able to execute simultaneously using one part
    per process or thread
  • In some cases, different parts are defined by one
    program, but in general they are defined by
    multiple programs
  • Cooperation is achieved through logically shared
    memory that is used to share information and to
    synchronize the operation of the constituent
    processes
  • The operating system should provide at least a
    base level mechanism to support sharing and
    synchronization among a set of processes

4
Operating System Concerns
  • Keep track of active processes done using
    process control block
  • Allocate and de-allocate resources for each
    active process (Processor time, Memory, Files,
    I/O devices)
  • Protect data and resources against unwanted
    interference from other processes
  • Programming errors done in one process should not
    affect the stability of other processes in the
    system
  • Result of process must be independent of the
    speed of execution of other concurrent processes
  • This includes process interaction and
    synchronization and it is subject of this
    presentation

5
Process Interaction
  • Processes unaware of each other
  • Independent processes that are not intended to
    work together i.e. two independent applications
    want to access same printer or same file the
    operating system must regulate these accesses
    these processes exhibit competition
  • Processes indirectly aware of each other
  • Processes that are not aware of each other by
    knowing each others process ID, but they are
    sharing some object (such as an I/O buffer) such
    processes exhibit cooperation
  • Process directly aware of each other
  • These are processes that are able to communicate
    to each other by means of process IDs they are
    usually designed to work jointly on some
    activity these processes exhibit cooperation

6
Competition Among Processes for Resources
  • Two or more processes need to access a resource
  • Each process is not aware of the existence of the
    other
  • Each process should leave the state of the
    resource it uses unaffected (I/O devices, memory,
    processor, etc)
  • Execution of one process may affect the execution
    of the others
  • Two processes wish access to single resource
  • One process will be allocated the resource, the
    other one waits (therefore slowdown)
  • Extreme case waiting process may never get
    access to the resource, therefore never terminate
    successfully
  • Control problems
  • Mutual Exclusion
  • Critical sections
  • Only one program at a time is allowed in a
    critical section
  • i.e. only one process at a time is allowed to
    send command to the printer
  • Deadlock
  • P1 and P2 with R1 and R2 each process needs to
    access both resources to perform part of its
    function R1 gets allocated to P2 and R2 gets
    allocated to P1 both processes will wait
    indefinitely for the resources deadlock
  • Starvation
  • P1, P2, P3 and resource R P1 and P3 take
    successively access to resource R P2 may never
    get access to it, even if there is no deadlock
    situation starvation

7
Cooperation Among Processes by Sharing
  • Processes that interact with other processes
    without being aware of them
  • i.e. multiple processes that have access to
    global variables, shared files or databases
  • The control mechanism must ensure the integrity
    of the shared data
  • Control problems
  • Deadlock
  • Starvation
  • Mutual exclusion
  • Data coherence
  • Data items are accessed in two modes read and
    write
  • Writing must be mutually exclusive to shared
    resources
  • Critical sections are used to provide data
    integrity

8
Cooperation Among Processes by Communication
  • When processes cooperate by communication,
    various processes participate in a common effort
    that links all of the processes
  • Communication provides a way to sync or
    coordinate the various activities
  • Communication can be characterized by
    sending/receiving messages of some sort
  • Mutual exclusion is not a control requirement
    since nothing is shared between process in the
    act of passing messages
  • Control problems
  • Possible to have deadlock
  • Each process waiting for a message from the other
    process
  • Possible to have starvation
  • Two processes sending message to each other while
    another process waits for a message

9
Example of Communication by Sharing problems
  • Process 1 KEYBOARD
  • Services the keyboard interrupts
  • The read characters are placed in a keyboard
    buffer
  • Process 2 DISPLAY
  • Displays the content of buffer on the monitor
  • Shared resources
  • Input buffer
  • Characters counter of how many chars in buffer
    and not displayed

10
KEYBOARD and DISPLAY processes
  • Keyboard Process
  • ld AC, counter
  • inc AC
  • store AC, counter
  • Display process
  • ld AC, counter
  • dec AC
  • store AC, counter
  • If KEYBOARD process is interrupted after
    instruction 1 (its registers (context) are
    saved and restored when gains the control of the
    CPU back) and the control passed to the process
    DISPLAY, the value of the counter variable will
    be altered, the two processes will continue to
    function improperly from this time forward
  • Causes for malfunction
  • The presence of two copies of same counter
    variable, one in memory and one in AC with
    different values
  • Parallel execution of the two processes
  • Situations where two or more processes are
    reading or writing some shared data and the final
    result depends on who runs precisely when, are
    called race conditions

11
Critical Sections
  • Are parts of the code (belonging to a process)
    that during execution has exclusive control over
    a system resource
  • It has a well defined beginning and end
  • During the execution of the critical section, the
    process cant be interrupted and the control of
    the processor given to another process that is
    using same system resource
  • At a given moment, there is just one active
    critical section corresponding to a given
    resource
  • A critical section is executed in mutual
    exclusion mode
  • Critical section examples
  • Value update for a global shared variable
  • Modification of a shared database record
  • Printing to a shared printer

12
Mutual Exclusion
  • If we could arrange matters so no two processes
    were ever in their critical regions at the same
    time, we could avoid race conditions
  • This requirement avoids race conditions, but is
    not sufficient for having parallel processes
    cooperate correctly and efficiently using shared
    data. Four conditions to achieve good results
  • No two processes may be simultaneously inside
    their critical regions (have mutual exclusion)
  • No assumption may be made about speeds and number
    of CPUs (independence of speed and number of
    processors)
  • No process outside critical section may block
    other processes (correct functionality is to be
    guaranteed if one of the processes is abnormally
    terminated outside of the critical section)
  • No process would have to wait forever to enter
    its critical section (the access in the critical
    section is guaranteed in a finite time)

13
Mutual Exclusion
  • While one process is busy updating shared memory
    (or modifying a shared resource) in its critical
    region, no other process will enter its critical
    region and cause trouble
  • There are a number of different approaches
  • Software approaches
  • Dekker Algorithm
  • Petersons Algorithm
  • Hardware approaches
  • Interrupt disabling
  • ISA modification

14
Dekkers Algorithm First Attempt
void proc2() while (TRUE) while (turn
PROC1) /critical section code /
turn PROC1 something_else()
void proc1() while (TRUE) while (turn
PROC2) /critical section code /
turn PROC2 something_else()
int turn /global variable/ main() turn
PROC1 init_proc(proc1(), ) init_proc(proc2()
, )
  • turn global memory location that both processes
    could access each process examines the value of
    turn, if it is equal to the number of process,
    then the process could proceed to the critical
    section
  • This procedure is known as busy waiting, since
    the processes are waiting (doing nothing
    productive but taking processor) to get the
    access to critical section
  • Mutual exclusion conditions
  • Satisfied
  • Unsatisfied processes can be executed
    alternatively only, thus, the rhythm of execution
    is given by the slower process
  • Unsatisfied abnormal termination of one process
    determines blocking of the other
  • Satisfied

15
Dekkers Algorithm Second Attempt
void proc1() while (TRUE) while (p2use
TRUE) p1use TRUE /critical
section code / p1use FALSE
something_else()
void proc2() while (TRUE) while (p1use
TRUE) p2use TRUE /critical
section code / p2use FALSE
something_else()
/global variables/ int p1use, p2use
main() p1use FALSE p2use
FALSE init_proc(proc1(), ) init_proc(proc2()
, )
  • The problem with first attempt is that it stores
    the name of the process that may enter its
    critical section, when in fact we need state
    information about both processes
  • Each process has to have its key to the critical
    section, so if one process fails, the other could
    still have access to the critical section
  • Mutual exclusion conditions
  • Unsatisfied if process proc1 is getting
    interrupted right before have set p1use TRUE,
    and the second process takes over the processor,
    then at one stage both processes will have access
    to the critical section
  • Satisfied
  • Satisfied if the processes are not failing in the
    critical section or during setting the flags
  • Satisfied

16
Dekkers Algorithm Third Attempt
void proc1() while (TRUE) p1use TRUE
while (p2use TRUE) /critical section code
/ p1use FALSE something_else()

void proc2() while (TRUE) p2use TRUE
while (p1use TRUE) /critical
section code / p2use FALSE
something_else()
int p1use, p2use /global variables/ main() p1u
se FALSE p2use FALSE init_proc(proc1(),
) init_proc(proc2(), )
  • Because one process could change its state after
    the other checked it, both processes could go in
    the critical section, so the second attempt
    failed
  • Perhaps we could change this with just changing
    the position of two statements
  • Mutual exclusion conditions
  • Satisfied
  • Satisfied
  • Satisfied if the processes are not failing in the
    critical section or during setting the flags
    Unsatisfied otherwise (the other process is
    blocking)
  • Unsatisfied if both processes set their flags
    to true before either of them has executed the
    while statement, then each will think that the
    other has entered its critical section, causing
    deadlock

17
Dekkers Algorithm Forth Attempt
void proc1() while (TRUE) p1use TRUE
while (p2use TRUE) p1use FALSE
delay() p1use TRUE /critical
section code / p1use FALSE
something_else()
void proc2() while (TRUE) p2use TRUE
while (p1use TRUE) p2use FALSE
delay() p2use TRUE
/critical section code / p2use FALSE
something_else()
int p1use, p2use /global variables/ main() p1u
se FALSE p2use FALSE init_proc(proc1(),
) init_proc(proc2(), )
  • Third algorithm failed because deadlock occurred
    as result of irreversibly change of each
    processs state to TRUE before actually having
    the test done. No way back off from this position
  • Try to fix this by having each process to
    indicate its desire to enter the critical
    section, but it is prepared to defer to the other
    process
  • Mutual exclusion conditions
  • Satisfied
  • Unsatisfied if the processes are executing with
    exact speed, then neither of the processes will
    enter the critical section
  • Satisfied if the processes are not failing in the
    critical section or during setting the flags
    Unsatisfied otherwise (the other process is
    blocking)
  • Satisfied

18
Dekkers Algorithm Correct Version
void proc1() while (TRUE) p1use TRUE
while (p2use TRUE) if (turn
PROC2) p1use FALSE while
(turn PROC2) p1use TRUE
/critical section/ turn PROC2
p1use FALSE something_else()
void proc2() while (TRUE) p2use TRUE
while (p1use TRUE) if (turn
PROC1) p2use FALSE while
(turn PROC1) p2use TRUE
/critical section code / turn
PROC1 p2use FALSE something_else()

int p1use, p2use, turn /global
variables/ main() p1use FALSE p2use
FALSE turn PROC1 init_proc(proc1(), )
init_proc(proc2(), )
  • It is an algorithm that respects the 4 conditions
    of mutual exclusion, but only for two concurrent
    processes.
  • Mutual exclusion conditions
  • Satisfied
  • Satisfied
  • Satisfied
  • Satisfied

19
Petersons Algorithm
void proc2() while (TRUE) p2use TRUE
turn PROC1 while (p1use TRUE
turnPROC1) /critical section/
p1use FALSE something_else()
void proc1() while (TRUE) p1use TRUE
turn PROC2 while (p2use TRUE
turnPROC2) /critical section/
p1use FALSE something_else()
  • If proc2 is in its critical section, then p2use
    TRUE and proc1 is blocked from entering its
    critical section.
  • Petersons Algorithm can be easily generalized
    for n threads
  • Mutual exclusion conditions
  • Satisfied
  • Satisfied
  • Satisfied
  • Satisfied

int p1use, p2use int turn main() p1use
FALSE p2use FALSE init_proc(proc1(), )
init_proc(proc2(), )
20
Hardware Solutions - Disabling Interrupts
  • Simplest solution is to have the process disable
    interrupts right after entering the critical
    region and enable them just before leaving it
  • With interrupts disabled, no interrupts will
    occur
  • The processor is switched from process to process
    only as result of interrupt occurrence, so the
    processor will not be switched to other process
  • It is unwise to give a user process the power to
    turn off interrupts
  • Suppose it did it and never turn them on again
  • Suppose it is a multi-processor system disabling
    interrupts on one of them, will not help too much
  • It is a useful technique within the operating
    system itself, but it is not appropriate as
    general mutual exclusion mechanism for user
    processes

while (TRUE) /disable interrupts/
/critical section/ /enable interrupts/
something_else()
21
Special Machine Instructions
  • In a multiprocessor configuration, several
    processors share access to a common main memory
    the processors behave independently
  • There is no interrupt mechanism between
    processors on which mutual exclusion can be based
  • At a hardware level, access to a memory location
    excludes any other access to same memory
    location based on this, several machine level
    instructions to help mutual exclusion have been
    added. Most common ones
  • Test Set Instruction
  • Exchange Instruction
  • Because those operations are performed in a
    single machine cycle, they are not subject to
    interference from other instructions

22
Test Set Instruction
/test set instruction / boolean testset (int
i) if (i0) i1 return TRUE
else return FALSE
void proc(int i) while (TRUE) while
(!testset(bolt)) /critical section/
bolt 0 something_else()
/number of processes/ const int n 2 int
bolt main() int i in bolt 0 while
(i gt0) init_proc(proc1(i), ) i--
  • The shared variable bolt is initialized to 0
  • The only process that may enter its critical
    section is the one that finds the bolt variable
    equal to 0
  • All processes that attempt to enter the critical
    section go into a busy waiting mode
  • When a process leaves the critical section, it
    resets bolt to 0 at this point only one from the
    waiting processes is granted access to the
    critical section

23
Exchange Instruction
/exchange instruction / void exchange (int
register, int memory) int temp temp
memory memory register register
temp
void proc(int i) int keyi while (TRUE)
keyi1 while (keyi ! 0)
exchange(keyi, bolt) /critical
section/ exchange (keyi, bolt)
something_else()
/number of processes/ const int n 2 int
bolt main() int i in bolt 0 while
(i gt0) init_proc(proc1(i), ) i--
  • The instruction exchanges the contents of a
    register with that of a memory location during
    the execution of the instruction, access to that
    memory location is blocked for any other
    instruction
  • The shared variable bolt is initialized to 0
    each process holds a local variable key that is
    initialized to 1
  • The only process that enters the critical section
    is the one that finds the variable bolt equal to
    0

24
Properties of Hardware Approach
  • Advantages
  • Simple and easy to verify
  • It is applicable to any number of processes on
    either a single processor or multiple processors
    sharing main memory
  • It can be used to support multiple critical
    sections, each critical section defined by its
    own global variable
  • Problems
  • Busy waiting is employed
  • Starvation is possible selection of a waiting
    process is arbitrary, thus some process could
    indefinitely be denied access
  • Deadlock is possible consider following
    scenario
  • P1 executes special instruction (testexchange)
    and enters its critical section
  • P1 is interrupted to give the processor to P2
    (which has higher priority)
  • P2 wants to use same resource as P1 so wants to
    enter critical section so, it will test the
    critical section variable and wait
  • P1 will never be dispatched again because it is
    of lower priority than another ready process, P2

25
Semaphores
  • Because of the drawback of both the software and
    hardware solutions, we need to look into other
    solutions
  • Dijkstra defined semaphores
  • Two or more processes can cooperate by means of
    simple signals, such that a process can be forced
    to stop at a specific place until it has received
    a specific signal
  • For signaling, special variables, called
    semaphores are used

26
Semaphores
  • Special variable called a semaphore is used for
    signaling
  • to transmit a signal, execute signal(s)
  • Dijkstra used V for signal (increment - verhogen
    in Dutch)
  • to receive a signal, execute wait(s)
  • Dijkstra used P for wait (test - proberen in
    Dutch)
  • If a process is waiting for a signal, it is
    suspended until that signal is sent
  • Wait and Signal operations cannot be interrupted
  • A queue is used to hold processes waiting on the
    semaphore

27
Semaphores Simplified view
  • We can view the semaphore as a variable that has
    an integer value three operations are defined
    upon this value
  • A semaphore may be initialized to a non-negative
    value
  • The wait operation decrements the semaphore
    value. If the value becomes negative, then the
    process executing wait is blocked
  • The signal operation increments the semaphore
    value. If the value is not positive, then a
    process blocked by a wait operation is unblocked

28
Semaphores Formal view
struct semaphore int count queueType
queue void wait(semaphore s) s.count--
if (s.count lt 0) place this process in
s.queue block this process void
signal(semaphore s) s.count if (s.count
lt 0) remove a process P from s.queue
place process P on ready list
  • A queue is used to hold processes waiting on a
    semaphore
  • What order should the processes be removed
  • Fairest policy is FIFO, a semaphore that
    implements this is called strong semaphore
  • A semaphore that doesnt specify the order in
    which processes are removed from the queue is
    known as week semaphore

29
Binary Semaphores
struct binary_semaphore enum (zero, one)
value queueType queue void
waitB(binary_semaphore s) if (s.value 1)
s.value 0 else place this process in
s.queue block this process void
signalB(semaphore s) if (s.queue.is_empty())
s.value 1 else remove a process P
from s.queue place process P on ready list
  • A more restrictive version of semaphores
  • A binary semaphore may take on the values 0 or 1.
  • In principle it should be easier to implement
    binary semaphores and they have expressive power
    as the general semaphore
  • Both semaphores and binary semaphores do have a
    queue to hold the waiting processes

30
Example of Semaphore Mechanism
  • Processes A, B and C depend on the results from
    process D
  • Initially, process D has produced an item of its
    resources and it is available (the value of the
    semaphore is s1)

31
  • (1) A is running, B, D and C are ready When A
    issues a wait(s) it will immediately pass the
    semaphore and will be able to continue its
    execution, so it rejoins the ready queue
  • (2) B runs and will execute a wait(s) primitive
    and it is suspended (allowing D to run)
  • (3) D completes a new result and issues a
    signal(s)

32
  • (4) signal(s) from (3) allows B to move in ready
    queue D rejoins the ready queue and C is allowed
    to run
  • (5) C is suspended when it issues a wait(s),
    similarly A and B are suspended on the semaphore
  • (6) D takes processor again and produces one
    reslut again, calling signal(s)
  • (7) C is removed from the semaphore queue and
    placed in ready list
  • Latter cycles of D will release A and B from
    suspension

33
Mutual Exclusion with Semaphores
/ program mutual exclusion / const int n 3
/ number of processes / semaphore lock
1 void P(int i) while (true)
waitB(lock) / critical section /
signalB(lock) / other processing/
void main() int i in while (igt0)
init_proc(proc(i), ) i--
34
Producer/Consumer Problem
  • Problem formulation
  • One or more producers generating some type of
    data (i.e. records, characters, etc) and placing
    these in a buffer
  • Consumer that are taking items out of the buffer,
    one at a time only one agent (either producer or
    consumer can access the buffer at a time)
  • The system is to be constrained to prevent the
    overlap of buffer operations
  • Examine a number of solutions to this problem

35
Infinite linear array buffer
producer while (true) / produce item v
/ Buffin v in
consumer while (true) while (in lt out)
/do nothing / w Buffout out /
consume item w /
  • Consumer has to make sure that will not read
    data from an empty buffer (makes sure in gtout)
  • Try to implement this using binary semaphores

Note shaded area indicates occupied locations
36
One producer, One consumer, Infinite buffer
void producer() while (TRUE)
produce_object() append()
signal(product) something_else()
main() create_semaphore(product) init_proc(pro
ducer(), ) init_proc(consumer(), )
void consumer while (TRUE)
wait(product) take() consume_object()
something else()
  • product is a semaphore that counts the number of
    objects placed in the buffer and not consumed yet
  • Product is (in out) (see the previous buffer)
  • This solution works only if there is just one
    consumer, one producer and the intermediary
    buffer is infinite. If multiple
    producers/consumers than the append() and take()
    need to be serialized (as they increment/decrement
    buffer pointers)

37
Multiple producers, Multiple consumers and
infinite buffer
main() create_semaphore(product) create_semaphor
e(buff_access_prod) create_semaphore(buff_access_
cons) init_proc(producer1(), )
init_proc(producer2(), ) // init_proc(pro
ducerN(), ) init_proc(consumer1(),
) init_proc(consumer2(), ) // init_proc(c
onsumerM(), )
void producerX() while (TRUE)
produce_object() wait(buff_access_prod)
append() signal(buff_access_prod)
signal(product) something_else()
void consumerY while (TRUE)
wait(product) wait(buff_access_cons)
take() signal(buff_access_cons)
consume_object() something else()
  • buff_access_prod is a semaphore that synchronizes
    the access of producers to the buffer
  • buff_access_cons is a sempahore that synchronizes
    the access of the consummers to the buffer
  • product is a semaphore that counts the produced
    objects yet unconsumed

38
Finite (circular) buffer
producer while (true) / produce item v /
/ do nothing while buffer full / while ((in
1)nout) Buffin v in (in 1) n
consumer while (true) / do nothing while no
data / while (in out) w
Buffout out (out 1) n / consume item
w /
  • Block
  • (i) Producer insert in full buffer
  • (ii) Consumer remove from empty buffer
  • Unblock
  • (i) Consumer remove item
  • (ii) Producer insert item

Note shaded area indicates occupied locations
39
Multiple producers, Multiple consumers, Finite
buffer
main() create_semaphore(product) create_semaphor
e(buff_access_prod) create_semaphore(buff_access_
cons) create_semaphore(buff_space) /initialize
the buff_space semaphor to the size of the
buffer/ init_proc(producer1(), )
init_proc(producer2(), ) // init_proc(pro
ducerN(), ) init_proc(consumer1(),
) init_proc(consumer2(), ) // init_proc(c
onsumerM(), )
void producerX() while (TRUE)
produce_object() wait (buff_space)
wait(buff_access_prod) append()
signal(buff_access_prod) signal(product)
something_else()
void consumerY while (TRUE)
wait(product) wait(buff_access_cons)
take() signal(buff_access_cons)
signal(buff_space) consume_object()
something else()
  • buff_space semaphore that counts the free space
    from the buffer
  • product semaphore that counts the produced
    items and not consumed yet
  • buff_access_prod is a semaphore that synchronizes
    the access of producers to the buffer
  • buff_access_cons is a semaphore that synchronizes
    the access of the consumers to the buffer

40
Semaphores implementation
  • As mentioned earlier, it is imperative that the
    wait and signal operations to be atomic
    primitives
  • The essence of the problem is mutual exclusion
  • Only one process at a time may manipulate a
    semaphore with either a wait or signal operation
  • Any of the software schemas would do (Petersons
    and Dekkers algorithms)
  • Large amount of processing overhead
  • The alternative is to use hardware supported
    schemas for mutual exclusion
  • Semaphores implemented with testset instruction
  • Semaphores implemented with disable/enable
    interrupts

41
Semaphores implementation with testset
wait(s) while (!testset(s.flag))/ do nothing
/ s.count-- if (s.count lt 0) /place
this process in s.queue block this
process/ s.flag 0
signal(s) while (!testset(s.flag)) /do
nothing/ s.count if (s.count lt 0)
/remove a process P from s.queue place
process P on ready list/ s.flag 0
  • The semaphore s is a structure, as explained
    earlier, but now includes a new integer
    component, s.flag
  • This involves a form of busy waiting, but the
    primitives wait and signal are short, so the
    amount of waiting time involved should be minor

42
Semaphores implemented using interrupts
wait(s) disable_interrupts() s.count--
if (s.count lt 0) /place this process in
s.queue block this process
enable_interrupts()
signal(s) disable_interrupts() s.count
if (s.count lt 0) /remove a process P from
s.queue place process P on ready list/
enable_interrupts()
  • For single processor system it is possible to
    inhibit the interrupts for the duration of a wait
    or signal operation
  • The relative short duration of these operations
    means that this approach is reasonable

43
Inter Process Communication
  • Inter process data exchange, execution state
    report, results collection is part of inter
    process communication it can be done using some
    shared memory zones, therefore synchronization is
    required
  • Semaphores are primitive (yet powerful) tools to
    enforce mutual exclusion and for process
    coordination still, it may be difficult to
    produce a correct program using semaphores
  • The difficulty is caused by the fact that wait
    and signal operations may be scattered throughout
    a program and is not easy to see an overall
    effect

44
Messages
  • When a process interacts with another, two main
    fundamental requirements must be satisfied
    communication and synchronization
  • Message passing provides both of those functions
  • Message-passing systems come in many forms this
    section will provide a general view of typical
    features found in such systems
  • The message-passing function is normally provided
    in the form of primitives
  • Send (destination, message)
  • Receive (source, message)

45
Messages design issues
  • Synchronization
  • Blocking vs. Non-blocking
  • Addressing
  • Direct
  • Indirect
  • Message transmission
  • Through value
  • Through reference
  • Format
  • Content
  • Length
  • Fixed
  • Variable
  • Queuing discipline
  • FIFO
  • Priority

46
Synchronization
  • Send gets executed in a process
  • Sending process is blocked until the receiver
    gets the message
  • Sending process continues its execution in a non
    blocking fashion
  • Receive gets executed in a process
  • If a message has been previously sent, the
    message is received and execution continues
  • If there is no waiting message then
  • Process can be blocked until a message arrives
  • The process continues to execute, abandoning the
    attempt to receive
  • So both the sender and receiver can be blocking
    or not

47
Synchronization
  • There are three typical combinations of systems
  • Blocking send, blocking receive
  • Both the receiver and sender are blocked until
    the message is delivered (provides tight sync
    between processes)
  • Non-blocking send, blocking receive
  • The sender can continue the execution after
    sending a message, the receiver is blocked until
    message arrives (it is probably the most useful
    combination)
  • Non-blocking send, non-blocking receive
  • Neither party waits
  • Typically only one or two combinations are
    implemented

48
Addressing
  • Direct addressing
  • Send primitive include the identifier of the
    receiving process
  • Receive can be handled in two ways
  • Receiving process explicitly designates the
    sending process (effective for cooperating
    processes)
  • Receiving process is not specifying the sending
    process (known as implicit addressing) in this
    case, the source parameter of receive primitive
    has a value returned when the receive operation
    has been completed
  • Indirect addressing
  • The messages are not sent directly from sender to
    receiver, but rather they are sent to a shared
    data structure consisting of queues that
    temporarily can hold messages those are referred
    to as mailboxes.
  • Two communicating process
  • One process sends a message to a mail box
  • Receiving process picks the message from the
    mailbox

49
Indirect process communication
  • Indirect addressing decuples the sender form the
    receiver allowing for greater flexibility.
  • Relationship between sender and receiver
  • One to one
  • Private communications link to be set up between
    two processes
  • Many to one
  • Useful for client server interaction one process
    provides services to other processes in this
    case, the mailbox is known as port
  • One to many
  • Message or information is broadcasted across a
    number of processes
  • Many to many

50
Message transmission
  • Through value
  • Require temp buffers in the operating system that
    would store the sent messages until the receiver
    would receive them
  • Overloading of the OS
  • Through reference
  • Doesnt require temporary buffers
  • Faster than the value passing method
  • Requires protection of the shared memory
  • It is difficult to implement when the sender and
    receiver are located on different machines
  • Mixed passing
  • The sending is done through reference
  • If it is the case (the receiver tries to modify
    the received message), the message gets
    transmitted again, this time through value

51
Message format
  • Fixed length
  • Easy to implement
  • Minimizes the processing and storage overhead
  • If large amount of data is to be sent, that data
    is placed into a file and the file is referenced
    by the message
  • Variable length
  • Message is divided in two parts header and body
  • Requires dynamic memory allocation, so
    fragmentation could occur

52
Queuing discipline
  • Simplest queuing discipline is first in first out
  • Sometime it is not enough, since some messages
    may have higher priority then others
  • Allow the sender to specify the message priority,
    either explicitly or based on some sort of
    message types
  • Allow the receiver to inspect the message queue
    and select which message to receive next

53
Mutual exclusion using messages
/ program mutualexclusion / void Proc(int i)
message msg while (true) receive (mutex,
msg) / critical section / send
(mutex, msg) / remainder /
void main() create_mailbox (mutex) /initialize
the mailbox with a null message/ send (mutex,
null) init_proc(proc(1), ) init_proc(proc(2)
, ) init_proc(proc(3), ) // init_proc(pro
c(N), )
  • We assume the using of a blocking receive
    primitive and a non-blocking send primitive
  • mutex is a shared mailbox, which can be used by
    all processes to send and receive
  • The mailbox is initialized to contain a single
    message with null content
  • A process wishing to enter its critical section,
    first attempts to receive a message it will be
    block if no message is in the mailbox once has
    aquired the message, it performs its critical
    section and then places a message back into the
    mailbox
  • The message functions as a token that is passed
    between process to process

54
Readers/Writers problems
  • There is a data area shared among a number of
    processes (i.e. file, bank of main memory, etc..)
  • There are a number of processes that only read
    the data area (readers) or write it (writers)
  • Conditions that must be satisfied
  • Any number of readers may simultaneously read the
    data
  • Only one writer at the time may write the data
  • If a writer is writing the data, no reader may
    read it
  • Note that this problem is not the same as the
    producer/consumer problem, since the readers only
    read data and the writers only write data the
    readers dont modify the data structures nor the
    writers read the data structures (to find out
    where to write).
  • Two solutions
  • Readers with priority
  • Writers with priority

55
Readers have priority
void readerX() while (TRUE)
wait(readcount_sem) readcount if
(readcount1) wait(write_sem) /block
the writers while read in progress/
signal(readcount_sem) READ_UNIT()
wait(readcount_sem) readcount--
if(readcount0) signal(write_sem)
//unblock writers signal(readcount_sem)

int readcount 0 main() create_semaphore(readco
unt_sem) create_semaphore(write_sem) /initializ
e the semaphores to 1/ signal(readcount_sem) sig
nal(write_sem) init_proc(reader1(), )
init_proc(reader2(), ) // init_proc(reade
rN(), ) init_proc(writer1(),
) init_proc(writer2(), ) // init_proc(wri
terM(), )
void writerY while (TRUE)
wait(write_sem) WRITE_UNIT()
signal(write_sem)
  • readcount_sem semaphore that synchronizes the
    access to the variable that keeps the number of
    parallel readers (readcount)
  • write_sem semaphore that controls the access of
    writers
  • As long as the writer is accessing the shared
    area, no other writers nor readers may access it

56
References
  • Operating Systems, William Stallings,
    ISBN 0-13-032986-X
  • Operating Systems A modern perspective, Garry
    Nutt, ISBN 0-8053-1295-1

57
  • Additional slides

58
Linux Fork()
  • fork()
  • returns 0 to child
  • return child_pid to parent
  • Parent is responsible to look after children
  • Failure to do so can create zombies
  • pid wait( status ) to explicitly wait for the
    child to terminate
  • signal(SIGCHLD, SIG_IGN) to ignore
    child-termination signals
  • May also set SIGCHLD to call a specified
    subroutine when a child dies

59
Fork() Example
/ Example of use of fork system call / include
ltstdio.hgt main() int pid int var 100
pid fork() if (pid lt 0) / error
occurred / fprintf(stderr, "Fork
failed!\n") exit(-1) else if (pid0)
/ child process / var 200 printf("I
am the child, pidd\n", getpid()) printf("My
child variable value is d\n",var) else
/ parent process / printf("I am the
parent, pidd\n", getpid() ) printf("My
parent variable value is d\n",var) exit(0)

60
System V Semaphores
  • Generalization of wait and signal primitives
  • Several operations can be done simultaneously and
    the increment and decrement operations can be
    values greater than 1
  • The kernel does all the requested operations
    atomically
  • Elements
  • Current value of the semaphore
  • Process ID of last process that operates on the
    semaphore
  • Number of processes waiting for the semaphore
    value to be greater than its current value
  • Number of processes waiting for the semaphore
    value to be zero
  • Associated with the semaphores are queues of
    processes suspended on that semaphore

61
System V Semaphores
  • Key - 4 byte value for the name
  • Create/access semaphores (you can create them in
    sets)
  • id semget( KEY, Count, IPC_CREAT PERM )
  • id semget( KEY, 0, 0 )
  • Perm file permission bits (0666)
  • to create only (fails if exists)
    use IPC_CREATIPC_EXCLPERM
  • Count of semaphores to create
  • Controlling semaphores
  • i semctl( id, num, cmd, )
  • id identifier of the semaphore set
  • num number of the semaphore to be processed
  • cmd type of command (GETVAL, SETVAL, GETPID )
  • - up to the type of command
  • i.e. - deleting semaphores
  • i semctl( id, 0, IPC_RMID, 0 )

62
Semaphore Operations (System V)
  • Operations on semaphores
  • semop(id, sembuf sops, nsops)
  • id identifier of the semaphore set
  • sops points to the user defined array of sembuf
    structures that contain the semaphore operations
  • nsops The number of sembuf structures in the
    array
  • Semaphore Structure
  • struct sembuf
  • short sem_num (semaphore ID)
  • short sem_op (change amount)
  • short sem_flg (wait/dont wait)
  • op
  • sem_flg can be 0 or IPC_NOWAIT
  • Wait()
  • op.sem_op -1 (decrement)
  • res semop( id, op, 1 )
  • Signal()
  • op.sem_op 1 (increment)
  • res semop( id, op, 1 )

63
Linux Semaphore (Posix)
  • int sem_init(sem_t sem, int pshared, unsigned
    int value)
  • int sem_wait(sem_t sem)
  • int sem_post(sem_t sem)
  • int sem_getvalue(sem_t sem, int val)
  • int sem_destroy(sem_t sem)

64
Shared Memory
  • Fastest way of inter process communication
  • It is a common block of virtual memory shared by
    multiple processes
  • Read and write of the shared memory is done using
    same read and write for normal memory
  • Permissions (read only or read/write) are
    determined per process basis
  • Mutual exclusion constrains are not provided by
    the shared memory, but they have to be programmed
    in the processes that are using it

65
Shared Memory
  • Create/Access Shared Memory
  • id shmget( KEY, Size, IPC_CREAT PERM )
  • id shmget( KEY, 0, 0 )
  • Deleting Shared Memory
  • i shmctl( id, IPC_RMID, 0 )
  • Or use ipcrm
  • Accessing Shared Memory
  • memaddr shmat( id, 0, 0 )
  • memaddr shmat( id, addr, 0 )
  • Addr should be multiple of SHMLBA
  • memaddr shmat( id, 0, SHM_READONLY )
  • System will decide address to place the memory at
  • shmdt( memaddr )
  • Detach from shared memory

66
Unix Pipes
  • Circular buffer allowing processes to communicate
    to each other following producer-consumer model
  • It is a first in first out queue, written by one
    process and read by another
  • When a pipe is created is given a fixed size in
    bytes
  • When a process attempts to write into the pipe,
    the write request is immediately executed if
    there is enough room otherwise, the process is
    blocked
  • Similarly, a read process is blocked if attempts
    to read more than it is in the pipe

67
Unix Pipes
  • Creates a one-way connection between processes
  • Created using pipe() call
  • Returns a pair of file descriptors
  • pend0 read end
  • pend1 write end
  • Use dup() call to convert to stdin/stdout
  • Example
  • int pend2
  • pipe( pend )
  • fork()
  • parent child
  • close(pend1) close(pend0)
  • write(pend1,)
  • read(pend0,)
  • close(pend0) close(pend1)

68
Unix Messages
  • Send information (type data) between processes
  • Message Structure
  • long type
  • char text
  • Functions
  • Create/access
  • id msgget( KEY, IPC_CREATIPC_EXCL)
  • id msgget( KEY, 0 )
  • Control
  • msgctl( id, IPC_RMID )
  • Send/receive
  • msgsnd( id, buf, text_size, flags )
  • msgrcv( id, buf, max_size, flags )
  • Useful Flags
  • IPC_NOWAIT
  • MSG_NOERROR (truncate long messages to max_size)

69
Semaphore example
include lterrno.hgt include ltpthread.hgt / Posix
Threads / include ltsemaphore.hgt / Posix
Semaphores / include ltstdarg.hgt include
ltstdio.hgt sem_t s / takes free format error
message much like printf, exits unconditionally
/ void errprint(const char fmt, ...)
va_list args va_start(args,fmt)
vfprintf(stderr, fmt, args) va_end(args)
exit(1) void MyThread(void arg) int
i printf("Entering MyThread\n") for (i
0 i lt 10 i) sem_wait(s)
printf("MyThread gets access to critical
section\n") fflush(stdout)
/some critical section code here/
sleep(2) sem_post(s)
pthread_exit( (void ) 0) return (void )
NULL
int main() int i / iteration variable /
int status / return status of calls /
pthread_t tid / Thread id / /
Semaphore initialization / sem_init(s,
/ the semaphore / 0,
/ is the semaphore shared or not?
(on Linux only non
shared sems are supported) /
1) / Initial semaphore value / /
Create and run the threads / status
pthread_create(tid, NULL, MyThread, (void )
NULL) if (status ! 0) errprint("MyThread
creation failed with d, errno d\n",
status, errno, strerror(errno)) /
Main continues execution, main is its own thread
/ for (i 0 i lt 15 i)
sem_wait(s) printf("Main gets access to
critical section\n") / some critical sectin
code / sleep(1) sem_post(s)
/ Wait for Thread Termination /
pthread_join(tid, NULL) if (status ! 0)
errprint("Thread join of MyTread failed with
d, errno d\n", status, errno,
strerror(errno))
70
Shared memory server
/----------------------------------------
Name main
Returns exit(EXIT_SUCCESS) or
exit(EXIT_FAILURE)
-----------------------------------------/ int
main() / shared memory segment id
/ int shMemSegID / shared
memory flags / int shmFlags
/ ptr to shared memory segment
/ char shMemSeg
/---------------------------------------/ /
Create shared memory segment / / Give
everyone read/write permissions.
/ /---------------------------------------/
shmFlags IPC_CREAT SHM_PERM if (
(shMemSegID shmget(SHM_KEY, SHM_SIZE,
shmFlags)) lt 0 ) perror("SERVER
shmget") exit(EXIT_FAILURE)
/-------------------------------------------/
/ Attach the segment to the process's data
/ / space at an address
/ / selected by the system.
/ /-------------------------------------------/
shmFlags 0 if ( (shMemSeg shmat(shMemSegID,
NULL, shmFlags)) (void ) -1 )
perror("SERVER shmat")
exit(EXIT_FAILURE)
/-------------------------------------- UNIX
header files --------------------
------------------/ include ltsys/types.hgt inclu
de ltunistd.hgt include ltfcntl.hgt include
ltsys/ipc.hgt include ltsys/stat.hgt include
ltsys/shm.hgt /------------------------------------
-- ISO/ANSI header files
--------------------------------------/ inclu
de ltstdlib.hgt include ltstdio.hgt include
ltstring.hgt include lttime.hgt include
lterrno.hgt /--------------------------------------
Constants
--------------------------------------/ /
value to fill memory segment / define
MEM_CHK_CHAR '' / shared memory key
/ define SHM_KEY
(key_t)1097 / size of memory segment (bytes)
/ define SHM_SIZE (size_t)256 /
give everyone read/write permission / / to
shared memory / define
SHM_PERM (S_IRUSR\ S_IWUSRS_IRGRPS_IWGRPS_IRO
THS_IWOTH)
71
Shared memory server
/-------------------------------------------/ /
Fill the memory segment with MEM_CHK_CHAR / /
for other processes to read
/ /-------------------------------------------/
memset(shMemSeg, MEM_CHK_CHAR,
SHM_SIZE) /-------------------------------------
----------/ / Go to sleep until some other
process changes / / first character
/ / in the shared memory
segment. / /--------------------
---------------------------/ while (shMemSeg
MEM_CHK_CHAR) sleep(1) /-------------------
-----------------------------/ / Call shmdt()
to detach shared memory segment.
/ /---------------------------------------------
---/ if ( shmdt(shMemSeg) lt 0 )
perror("SERVER shmdt") exit(EXIT_FAILURE)
/----------------------------------------------
----/ / Call shmctl to remove shared memory
segment. / /--------------------------------
------------------/ if (shmctl(shMemSegID,
IPC_RMID, NULL) lt 0) perror("SERVER
shmctl") exit(EXIT_FAILURE) exit(EXIT_S
UCCESS) / end of main() /
72
Shared memory client
/------------------------------------- UNIX
header files ---------------------
----------------/ include ltsys/types.hgt include
ltsys/stat.hgt include ltsys/ipc.hgt include
ltsys/shm.hgt /------------------------------------
- ISO/ANSI header files
-------------------------------------/ includ
e ltstdlib.hgt include ltstdio.hgt include
ltstring.hgt include lterrno.hgt /------------------
------------------- Constants
-------------------------------------
/ / memory segment character value
/ define MEM_CHK_CHAR '' / shared
memory key / define SHM_KEY
(key_t)1097 define SHM_SIZE
(size_t)256 / size of memory segment (bytes)
/ / give everyone read/write
/ / permission to shared memory
/ define SHM_PERM (S_IRUSRS_IWUSR\ S_IRGRPS_
IWGRPS_IROTHS_IWOTH)
/------------------------------------ Name
main Returns
exit(EXIT_SUCCESS) or
exit(EXIT_FAILURE) ----------------------
--------------/ int main() / loop counter
/ int i
/ shared memory segment id /
int shMemSegID / shared memory
flags / int shmFlags
/ ptr to shared memory segment /
char shMemSeg / generic char
pointer / char cptr
/-------------------------------------/
/ Get the shared memory segment for / /
SHM_KEY, which was set by / / the
shared memory server.
/ /-------------------------------------/
shmFlags SHM_PERM if ( (shMemSegID
shmget(SHM_KEY, SHM_SIZE, shmFlags)) lt 0 )
perror("CLIENT shmget") exit(EXIT_FAILURE)

73
Shared memory client
/-----------------------------------------/ /
Attach the segment to the process's / /
data space at an address / /
selected by the system.
/ /-----------------------------------------/ s
hmFlags 0 if ( (shMemSeg shmat(shMemSegID,
NULL, shmFlags)) (void ) -1 )
perror("SERVER shmat")
exit(EXIT_FAILURE) /--------------------------
-----------------/ / Read the memory segment
and verify that / / it contains the values
/ / MEM_CHK_CHAR and print them
to the screen / /-------------------------------
------------/ for (i0, cptr shMemSeg i lt
SHM_SIZE i, cptr) if ( cptr !
MEM_CHK_CHAR ) fprintf(stderr, "CLIENT
Memory Segment corrupted!\n")
exit(EXIT_FAILURE) putchar( cptr
) / print 40 columns across /
if ( ((i1) 40) 0 )
putchar('\n') putchar('\n')
/--------------------------------------------/ /
Clear shared memory segment.
/ /--------------------------------------------
/ memset(shMemSeg, '\0', SHM_SIZE) /--------
----------------------------------/ / Call
shmdt() to detach shared / / memory
segment.
/ /------------------------------------------/
if ( shmdt(shMemSeg) lt 0 )
perror("SERVER shmdt")
exit(EXIT_FAILURE) exit(EXIT_SUCCESS) /
end of main() /
74
Pipe example
int main() char buffer80 int pfid2 /
the pipe file descriptors / int status
status pipe(pfid) if (status -1)
error("Bad pipe call") status fork() /
create 2 processes / if (status -1)
error("Bad fork call") else if (status
0) /child process/ status
read(pfid0, buffer, sizeof(buffer)) if
(status ! sizeof(buffer)) error("Bad read
from pipe") printf("Child pid d
received the message ltsgt\n", getpid(), buffer)
status close(pfid0) / close the reader
end / else /parent process/
sprintf(buffer, "Pid of the Parent is ltdgt",
getpid()) status write(pfid1, buffer,
sizeof(buffer)) if (status !
sizeof(buffer)) error("Bad write to
pipe") status close(pfid1) /
close the writer end /
include lterrno.hgt include ltstdio.hgt include
ltunistd.hgt void error(char mesg)
fprintf(stderr, "Error ltsgt errno d
Write a Comment
User Comments (0)
About PowerShow.com