volatile total = 0;
void add()
{
void sub()
{
loadaddr R8 total
loadaddr R10 total
lw R9 0(R8)
lw R11 0(R10)
for (i=0; i<N; i++)
{
for (i=0; i<N; i++)
{
add R9 1
sub R11 1
}
}
sw R9 0(R8)
sw R11 0(R10)
}
}
Without volatile the compiler could optimize the code. If one thread executes
add
and another executes
sub
, what is the value of
total
when they have
finished?
CS350
Operating Systems
Fall 2013
Synchronization
8
The use of volatile
/
*
What if we DO NOT use volatile
*
/
int --------
volatile total = 0;
void add()
{
void sub()
{
loadaddr R8 total
loadaddr R10 total
lw R9 0(R8)
lw R11 0(R10)
add R9 N
sub R11 N
sw R9 0(R8)
sw R11 0(R10)
}
}
The compiler could aggressively optimize the code., Volatile tells the com-
piler that the object may change for reasons which cannot be determined
from the local code (e.g., due to interaction with a device or because of an-
other thread).
CS350
Operating Systems
Fall 2013
21

Synchronization
9
The use of volatile
/
*
Note the use of volatile
*
/
int ________
volatile total = 0;
void add()
{
void sub()
{
loadaddr R8 total
loadaddr R10 total
for (i=0; i<N; i++)
{
for (i=0; i<N; i++)
{
lw R9 0(R8)
lw R11 0(R10)
add R9 1
sub R11 1
sw R9 0(R8)
sw R11 0(R10)
}
}
}
}
The volatile declaration forces the compiler to load and store the value on
every use. Using volatile is necessary but not sufficient for correct behaviour.
Mutual exclusion is also required to ensure a correct ordering of instructions.
CS350
Operating Systems
Fall 2013
Synchronization
10
Ensuring Correctness with Multiple Threads
/
*
Note the use of volatile
*
/
int volatile total = 0;
void add()
{
void sub()
{
int i;
int i;
for (i=0; i<N; i++)
{
for (i=0; i<N; i++)
{
Allow one thread to to execute and make others wait
total++;
total--;
Permit one waiting thread to continue execution
}
}
}
}
Threads must enforce mutual exclusion.
CS350
Operating Systems
Fall 2013
22

Synchronization
11
Critical Section Example (Part 1)
int list
remove
front(list
*
lp)
{
int num;
list
element
*
element;
assert(!is
empty(lp));
element = lp->first;
num = lp->first->item;
if (lp->first == lp->last)
{
lp->first = lp->last = NULL;
}
else
{
lp->first = element->next;
}
lp->num_in_list--;
free(element);
return num;
}
The
list
remove
front
function is a critical section. It may not work
properly if two threads call it at the same time on the same
list
. (Why?)
CS350
Operating Systems
Fall 2013
Synchronization
12
Critical Section Example (Part 2)
void list
append(list
*
lp, int new
item)
{
list
element
*
element = malloc(sizeof(list
element));
element->item = new
item
assert(!is
in
list(lp, new
item));
if (is
empty(lp))
{
lp->first = element; lp->last = element;
}
else
{
lp->last->next = element; lp->last = element;
}
lp->num
in
list++;
}
The
list
append
function is part of the same critical section as
list
remove
front
.
It may not work properly if two threads call
it at the same time,
or if a thread calls it while another has called
list
remove
front
CS350
Operating Systems
Fall 2013
23

Synchronization
13
Enforcing Mutual Exclusion
•
mutual exclusion algorithms ensure that only one thread at a time executes the
code in a critical section
•
several techniques for enforcing mutual exclusion
–
exploit special hardware-specific machine instructions, e.g.,
test-and-set
,
compare-and-swap
, or
load-link / store-conditional
, that are intended for
this purpose
–
use mutual exclusion algorithms, e.g.,


You've reached the end of your free preview.
Want to read all 168 pages?
- Winter '10
- TIMBRECHT
- Operating Systems