0% found this document useful (0 votes)
5 views

L-06

The document discusses concurrency problems arising from multithreading and signal handling, emphasizing the need for atomic operations to ensure data integrity. It defines critical sections and outlines various solutions to implement them, including hardware and software approaches. Correct implementations must satisfy properties like mutual exclusion, progress, and bounded waiting to effectively manage concurrent access to shared resources.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

L-06

The document discusses concurrency problems arising from multithreading and signal handling, emphasizing the need for atomic operations to ensure data integrity. It defines critical sections and outlines various solutions to implement them, including hardware and software approaches. Correct implementations must satisfy properties like mutual exclusion, progress, and bounded waiting to effectively manage concurrent access to shared resources.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 16

Synchronization

Concurrency Problems
A statement like w-- in C (or C++) is implemented by several machine
instructions:
ld r4, #w
add r4, r4, -1
st r4, #w
Now, imagine the following sequence, what is the value of w?

ld r4, #w C.S. ______________


______________ ld r4, #w
______________ add r4, r4, -1
______________ st r4, #w
add r4, r4, -1
st r4, #w
Concurrency Problems
int w = 4;
main() {
______________

ld r4, #w
w--;
signal posted

add r4, r4, -1
}
st r4, #w
sig_handler() {

w--;
}
Concurrency Problems

Concurrency problem can occur in user-programs because of:


Multithreading
Two threads may modify the same variables concurrently
Signal handling (single-threaded or multithreaded)
If the program receives a signal in the middle of modifying a global
variable and the signal handler modifies that variable
Operating system kernels
The kernel could be multithreaded (as in multiprocessors)
Interrupt handling (single threaded or multithreaded)
An interrupt may occur in the middle of modifying a kernel data structure
The Fundamental Issue

In all these cases, what we thought to be an atomic operation


is not done atomically by the machine

Definition: An atomic operation is one that executes to


completion without any interruption or failure

An atomic operation has “an all or nothing” flavor:


Either it executes to completion, or
it did not execute at all, and
it executes without interruptions
Critical Sections

A critical section is an abstraction that


consists of a number of consecutive program instructions
all code within the section executes atomically
In the previous example, the w-- statement should be placed in
a critical section
Critical sections are used profusely in an OS to protect data
structures
Queues
shared variables
interrupt handlers
Solutions

There are many solutions to implement critical sections:


Hardware vs. software
some solutions require hardware support, kernel support, a
combination thereof, or no special support
Multithreaded vs. single-threaded
some solutions are for single-threaded only
Busy waiting vs blocking
in busy-waiting (spin-locks), a thread retains the CPU, and loops until
it can enter the critical section
in blocking, a thread gives up the CPU, and waits on some queue until
it gets notified that it can enter the critical section
Solution Criteria

A critical section implementation must be:


correct: only one thread can execute in the critical section
at any given time
efficient: getting into and out of the critical section must
be fast
concurrency control: a good implementation allows
maximum concurrency while preserving correctness
flexible: a good implementation must have as few
restrictions as practically possible
Solution Correctness

A correct solution to the critical section problem must satisfy:


1. Mutual exclusion: if a thread executes in a critical section,
no other threads can be executing in that critical section (at
most one)
2. Progress: If no thread currently executes in a critical section,
and there is one more thread that wish to execute the C.S.,
then one of them is allowed in (at least one)
3. Bounded waiting: There is a bound on the number of times
that other threads are allowed to enter the critical section
after a thread has made a request to enter and before that
request is granted
Solution Varieties

Hardware-based solutions
Spinlocks
Blocking synchronization
Solution 1 (Two Threads)

Thread T1 Thread T2

turn = T1; turn = T2;

while(turn ¹ T1) while(turn ¹ T2)


; ;
/* enter C.S. */ /* enter C.S. */
/* leave C.S. */ /* leave C.S. */
turn = T2; turn = T1;

Is this correct? Discuss the three correctness properties


Solution 2 (Two Threads)

Thread T1, Thread T2,


Flag[T1..T2]

Flag[T1] = true; Flag[T2] = true;

while(Flag[T2]) while(Flag[T1])
; ;
/* enter C.S. */ /* enter C.S. */
/* leave C.S. */ /* leave C.S. */
Flag[T1] = false; Flag[T2] = false;
Solution 3 (Two Threads)

Thread T1 Thread T2
Flag[T1..T2], turn

Flag[T1] = true; Flag[T2] = true;


turn = T2; turn = T1;
while(Flag[T2] and turn == T2) while(Flag[T1] and turn == T1)
; ;
/* enter C.S. */ /* enter C.S. */
/* leave C.S. */ /* leave C.S. */
Flag[T1] = false; Flag[T2] = false;
Disabling Interrupts

For a single-threaded system, interrupts are the only source of


concurrency problems (hardware or software)
It follows that a simple solution to implement critical section
is:
Disable interrupts at beginning of critical section
Enable interrupts at the end of critical section
For OS’es, disabling hardware interrupts is very dangerous
Can lead to delaying response to an important event
Prevent the OS from being used in a multiprocessor
Critical sections must be kept short
Synchronization Instructions

Relying on test-and-set instructions


implemented in hardware
it’s a machine instruction that:
reads a value from memory
tests the value against some constant
if the test true it sets the value in memory to a different value
reports the result of the test in a flag (e.g. carry or zero flag)
This instruction executes atomically
it locks the memory bus while executing
does not scale very well in multiprocessor environments with a shared
bus
Example

lock = 0;

while(! test-and-set(lock, 0, 1));


w--;
lock = 0;

Works because of the direct hardware support for atomicity


multithreaded or single threaded environments
must be used with care
does not scale to large number of threads/processors

You might also like