Process Synchronisation – Part 2/2
Lecture 5
Soumyabrata DEV
https://soumyabrata.dev/
Implementations
There are three basic mechanisms for implementing mutual
exclusion in critical sections
1. Semaphores
• Simple, but hard to program with
• Very low level
2. Monitors
• Higher level mechanism
• Requires higher-level programming languages
3. Messages
• Synchronisation without shared memory
• Uses Interprocess Communication (IPC) messages instead
2
Semaphores
3
Semaphore
• Semaphores are a fundamental synchronization mechanism in
operating systems and concurrent programming.
• Semaphores are synchronization primitives used to manage access to
shared resources and coordinate the execution of multiple processes
or threads in a concurrent environment.
4
Semaphore
• Semaphore is simply a variable which is non-negative and shared
between threads.
• This variable is used to solve the critical section problem and to
achieve process synchronization in the multiprocessing environment.
5
Semaphore
Semaphores are of two types:
• Binary Semaphore – This is also known as mutex lock. It can have
only two values – 0 and 1. Its value is initialized to 1. It is used to
implement the solution of critical section problem with multiple
processes.
• Counting Semaphore – Its value can range over an unrestricted
domain. It is used to control access to a resource that has multiple
instances.
6
Binary Semaphore
• A binary semaphore, also known as a mutex (short for mutual
exclusion), has two possible values: 0 and 1.
• It is often used to protect critical sections of code or shared
resources.
• When a process or thread acquires a binary semaphore, it sets it to 1
(indicating that the resource is locked). If the semaphore is already 1,
subsequent attempts to acquire it will block until it is released (reset
to 0) by the owning entity.
7
Counting Semaphore
• A counting semaphore can have values greater than 1, typically
representing the number of available instances of a resource.
• It is used for scenarios where multiple processes or threads can
access a shared resource concurrently, up to a specified limit.
• When a process or thread acquires a counting semaphore, the
semaphore's value decreases. When it releases the semaphore, the
value increases.
8
Semaphore Operations
Semaphore operations typically include:
• Wait (P) Operation: Decrements the semaphore value. If the value
becomes negative, the process or thread is blocked until the
semaphore becomes non-negative.
• Signal (V) Operation: Increments the semaphore value. If any
processes or threads were waiting, one of them is unblocked.
9
Semaphore
A semaphore S is an integer variable that can be accessed only through
two standard operations : wait() and signal().
The wait() operation reduces the value of semaphore by 1 and the
signal() operation increases its value by 1.
wait(S){
while(S<=0); // busy waiting
S--;
}
signal(S){
S++;
}
10
The Producer/Consumer Problem
• This is a common synchronisation problem
• Consider a producer process supplying a resource
to a consumer process
• Producer: creates instances of a resource
• Consumer: uses up instances of a resource
11
The Producer/Consumer Problem
• Producer and consumer share a buffer
• The producer put resources into the buffer
• The consumer takes resources from the buffer
• The buffer has a finite size
12
Problem Constraints
• The consumer must wait for producer if the buffer
is empty
• Producer must wait for consumer if the buffer is full
13
Synchronisation
• We need to keep the producer and consumer
synchronised
• The buffer is the critical section in this problem
• We usually need mutually exclusive access to the buffer
14
P/C Solution with Semaphores
Initialization of semaphores
mutex = 1
Full = 0 // Initially, all slots are empty. Thus
full slots are 0
Empty = n // All slots are empty initially
15
P/C Solution with Semaphores
Solution for Producer
do{
//produce an item Explanation:
When producer produces an item then the
wait(empty);
value of “empty” is reduced by 1 because
wait(mutex); one slot will be filled now. The value of
mutex is also reduced to prevent consumer
//place in buffer to access the buffer. Now, the producer has
placed the item and thus the value of “full”
signal(mutex); is increased by 1. The value of mutex is
signal(full); also increased by 1 because the task of
producer has been completed and
}while(true) consumer can access the buffer.
16
P/C Solution with Semaphores
Solution for Consumer
do{
wait(full); Explanation:
wait(mutex);
As the consumer is removing an item from
buffer, therefore the value of “full” is
// remove item from reduced by 1 and the value is mutex is also
buffer reduced so that the producer cannot
access the buffer at this moment. Now, the
signal(mutex); consumer has consumed the item, thus
signal(empty); increasing the value of “empty” by 1. The
value of mutex is also increased so that
// consumes item producer can access the buffer now.
}while(true)
17
Monitors
18
The Problem with Semaphores
• Semaphores are nice but they have an important
problem
• Using more than one semaphore can lead to deadlocks, if
order of wait() and signal() are not correctly set
• It is difficult to program with semaphores
Deadlocks are where processes or threads are stuck
waiting for resources that will never become available.
19
Monitors
• Monitors are higher-level sync primitives
• A monitor is a collection of procedures, variables and
data grouped together in a special kind of structure
• Their aim is to avoid the problems that can arise when
protecting critical sections with semaphores
20
Monitors
• Monitors are a synchronization mechanism that
encapsulates both data and the procedures (methods)
that operate on that data within a single programming
construct.
Basic Structure of a Monitor
A monitor typically consists of:
• Shared data: Variables that represent the shared resource or state.
• Procedures (methods): Operations that can be performed on the shared
data.
• Condition variables: Used for signaling and waiting within the monitor.
21
Example Monitor
monitor example {
int i; (Internal data)
condition c; (Condition variable)
void p() { (Monitor procedure)
...
}
}
22
Monitor Rules
• Processes may call monitor procedures whenever they wish
• Processes can’t access internal monitor data (variables, etc.) using
external procedures
23
Monitor Rules
• Only one process can be active inside a monitor
• Mutual exclusion inside the monitor is guaranteed by the compiler
24
Blocking in Monitors
• Mutual Exclusion is implemented using internal condition variables
• Conditions have two operations
• Wait
• Signal
25
wait(condition)
• This is executed when the monitor discovers that a process cannot
proceed
• The monitor blocks a process calling wait() and makes it wait on condition
• Another process can then be allowed into the monitor
• A process that calls wait() is always blocked
26
signal(condition)
• This is executed to wake up a process that is waiting
on condition
• After executing signal() the calling process must exit
the monitor immediately
• This guarantees mutual exclusion
27
Monitor for Producer/Consumer
• Requires two conditions:
• Buffer is full
• Buffer is empty
• Requires some internal data so we know when it is
empty or full
28
Monitor for Producer/Consumer
• Requires two operations
• Put a message in the buffer
• Remove a message from the buffer
29
Producer and Consumer Code
• Simplest possible consumer and producer code
• Monitor takes care of any issues, not producer or consumer
30
Benefits of Monitors
• Abstraction: Monitors provide an abstract and structured way to
handle synchronization, reducing the complexity of concurrent
programming.
• Safety: They help prevent common synchronization errors like data
races and deadlocks.
• Encapsulation: The encapsulation of data and procedures within a
monitor promotes clean and modular code design.
31
Drawbacks of Monitors
• Monitors are a high-level abstraction and may not be suitable for all
types of concurrent applications, especially in low-level or embedded
systems.
• Proper use of monitors requires understanding and adhering to
monitor-specific programming practices.
32
Messages
33
Messages System
Messages in operating systems refer to a mechanism used for
interprocess communication (IPC), allowing different processes or
threads to exchange data, request services, and synchronize their
activities within a computer system.
Message Components
A message typically consists of two main components:
• Message Header: Contains metadata about the message, including
the sender's identity, the recipient's identity, message type, and
other control information.
• Message Body: Carries the actual data or payload of the message,
which can be of various types, such as commands, requests,
responses, or simple data.
34
Messages System
• Synchronisation with both semaphores and monitors relies on shared
memory
• The message system is a mechanism for inter-process communication
(IPC), that can also be relied upon for synchronisation without having
to share memory
35
Message System
• Elements in the message system:
• message: information that can be exchanged between two (or more)
processes or threads
• mailbox: a place where messages are stored between the time they are sent
and the time they are received
36
Message System Scheme
m Scheme
• Process A sends messages to process B using a mailbox
sends messages to process B using a mail
messages
send receive
A B
mailbox
a pipe can be implemented with messages 37
Message System Scheme
• One process or the other owns the data
• Never two at the same time
• If processes need to send messages both ways, we need two
mailboxes
38
Message System Operations
• Two basic operations
• send(mailbox, message)
• Put a message in the mailbox
• receive(mailbox, message)
• Remove a message from the mailbox
• In practice we also need the system calls create(mailbox) and
delete(mailbox)
39
Message System Addressing
• The message identifies source and destination
processes
• Through their PIDs
• There may be multiple destinations, or destination
may be unspecified
40
Message Format
• Depends on the objectives of the system
• fixed-length: minimise processing and storage overhead
• variable-length: more flexible approach for operating
systems
41
Why Use Messages?
• Communicating processes sometimes need to be
separate
• They do not trust each other
• The programs were written at different times by different
programmers who knew nothing about each other
• They run on different processors
• Less error-prone without shared memory
42
Mutual Exclusion with Messages
• Mutual exclusion must be guaranteed solely relying
on the mailbox
• Two levels of synchronisation in a message system
• Producer/Consumer Constraints
• Execution flow constraints
43
Producer/Consumer Constraints
• receive()
• Calling process waits when the mailbox is empty until a
message is added
• send()
• Calling process waits when mailbox is full until there is
space for another message
44
Execution Flow Constraints
• Send and receive: could be blocking or non-blocking
• Blocking send: when a process sends a message it blocks
until the message is received at the destination.
• Non-blocking send: After sending a message the sender
continues with its processing without waiting for it to
reach the destination
45
Execution Flow Constraints
• Send and receive: could be blocking or non-blocking
• Blocking receive: When a process executes a receive it
waits blocked until the receive is completed and the
required message is received
• Non-blocking receive: The process executing the receive
proceeds without waiting for the message
46
Execution Flow Constraints
• The most common combination is that of
• Blocking Receive
• Non-blocking send
47
Mutual Exclusion using Messages
• Mutual exclusion can be achieved using a single shared mailbox
• Processes can enter the critical section whenever they receive a
message
• Whenever they leave the critical section they must send a new
message to the mailbox
48
Producer/Consumer Algorithm Using Messages
• Not only we need to ensure mutual exclusion but
also to keep a count
• For this two mailboxes are needed
• one mailbox for consumers: data produced and consumed
• one mailbox for producers: accountancy purposes
49
Producer/Consumer Algorithm Using Messages
• Producers generate data and send it to the
consumers's mailbox
• Only when the producer’s mailbox indicates there is at
least one free slot in the buffer
• Consumers take messages from the consumer’s
mailbox when available
• Then send empty messages to the producer’s mailbox to
signal new free slot
50
Thank you!
See you next class!
25 September, Monday, 9:55am to 11:30am, TB3-105
51