Sie sind auf Seite 1von 26

Bounded

Buffer
Enrique Anicoche
Mitchel Cabarrubias
Jenielle Calimlim
Bless Ann de Vera

Background
Concurrent access to shared data may
result in data inconsistency.
Maintaining data consistency requires
mechanisms to ensure the orderly
execution of cooperating processes.

Cooperating Process

Can affect or be affected by other


processes executing in the system.
Can either directly share a logical
address space (that is, both code
and data) or be allowed to share
data only through files and
messages.

Race Condition

An undesirable situation when a


system attempts to perform two
or more situations at the same
time, operations must be done in
proper sequence.

Critical
Section Problem
To design a protocol that the
processes can use to cooperate.

Requirements needed to be
satisfied in creating a Critical
Problem Solution

1. Mutual Exclusion
2. Progress
3. Bounded Waiting

2 General Approach to
Handle Critical Section
Problems:
1. Preemptive Kernels
2. Non-preemptive
Kernels

Shared Data
#define BUFFER_SIZE 10
typedef struct {
...
} item;
item buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
int counter = 0;

Producer Process
item nextProduced;
while (1) {
while (counter ==
BUFFER_SIZE)
; /* do nothing */
buffer[in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
counter++;
}

Consumer Process
item nextConsumed;
while (1) {
while (counter == 0)
; /* do nothing */
nextConsumed = buffer[out];
out = (out + 1) %
BUFFER_SIZE;
counter--;
}

The Statements
counter++;
counter--;
must be performed atomically.

Atomic operation means an


operation that completes in its
entirety without interruption.

The Statements
The statement count++ may be
implemented in machine language as:
register1 = counter
register1 = register1 + 1
counter = register1
The statement count may be
implemented as:
register2 = counter
register2 = register2 1
counter = register2

The Statements
If both the producer and consumer
attempt to update the buffer
concurrently, the assembly language
statements may get interleaved.
Interleaving depends upon how the
producer and consumer processes
are scheduled.

Mutex Locks
We use the mutex lock to protect
critical regions and thus prevent
race conditions.
A process must acquire the lock
before entering a critical section; it
releases the lock when it exits the
critical section.

Has a boolean variable


available whose value
indicates if the lock is
available or not.
A process that attempts to
acquire an unavailable lock
is blocked until the lock is
released.

Thread
1

Wait
Release

MUTEX
Wait
Release

Thread
2

Advantages:
a.] Priority Inversion
Safety
b.] Deletion Safety

Semaphores
Synchronization tool that does not
require busy waiting.
Semaphore S integer variable.
Can only be accessed via two
indivisible (atomic) operations.

Semaphores
wait (S):
while S 0 do
no-op;
S--;
signal (S):
S++;

Semaphores
Implementation
Define
a semaphore as a record

typedef struct {
int value;
struct process *L;
} semaphore;
Assume two simple operations:
Block suspends the process that
invokes it.
Wakeup(P) resumes the execution
of a blocked process P.

Semaphores
Implementation
Implementation
Semaphore operations now defined

as
wait(S):
S.value--;
if (S.value < 0) {
add this process to S.L;
block;
}
signal(S):
S.value++;
if (S.value <= 0) {
remove a process P from S.L;
wakeup(P);
}

Two Types of Semaphores

Counting Semaphore integer value


can range over an unrestricted
domain.
Binary Semaphore integer value
can range only between 0 and 1; can
be simpler to implement.
Can implement a counting
semaphore S as a binary semaphore.

Problem

Suppose we have a circular buffer with


two pointers in and out to indicate the
next available position for depositing
data and the position that contains the
next data to be retrieved. See the
diagram below. There are two groups of
threads, producers and consumers. Each
producer deposits a data items into the in
position and advances the pointer in, and
each consumer retrieves the data item in
position out and advances the pointer
out.

Problem
A producer must wait until the
buffer is not full, deposit its data,
and then notify the consumers that
the buffer is not empty.
A consumer, on the other hand,
must wait until the buffer is not
empty, retrieve a data item, and
then notify the producers that the
buffer is not full