counter++ could be implemented as
register1 = counter
register1 = register1 + 1
counter = register1
counter– could be implemented as
register2 = counter
register2 = register2 - 1
counter = register2
Consider this execution interleaving with “count = 5” initially:
S0: producer execute register1 = counter {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 = 6}
S2: consumer execute register2 = counter {register2 = 5}
S3: consumer execute register2 = register2 – 1 {register2 = 4}
S4: producer execute counter = register1 {counter = 6 }
S5: consumer execute counter = register2 {counter = 4}
Each process has critical section segment of code
When one process in critical section, no other may be in its critical section
Each process must ask permission to enter critical section in entry section, may follow critical section with exit section, then remainder section
General structure of typical process
two approaches are used to handle critical-sections in OS:
while (true) {
flag[i] = true;
turn = j;
while (flag[j] && turn == j);
"critical section"
flag[i] = false;
"remainder section"
}
How a computer architecture determines what memory guarantees it will provide to an application is called memory model.
two categories of memory model
Memory barriers fences: Instructions to force any changes in memory to be propagated to all other processors.
boolean test_and_set (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv:
}
do {
while (test_and_set(&lock))
; /* do nothing */
/* critical section */
lock = false;
/* remainder section */
} while (true);
do {
waiting[i] = true;
key = true;
while (waiting[i] && key)
key = test_and_set(&lock);
waiting[i] = false;
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = false;
else
waiting[j] = false;
/* remainder section */
} while (true);
int compare and swap(int *value, int expected, int new value) {
int temp = *value;
if (*value == expected)
*value = new value;
return temp;
}
do {
while (compare and swap(&lock, 0, 1) != 0)
; /* do nothing */
/* critical section */
lock = 0;
/* remainder section */
} while (true);
acquire() {
while (!available)
; /* busy wait */
available = false;;
}
release() {
available = true;
}
do {
acquire lock
critical section
release lock
remainder section
} while (true);
P1:
S1;
signal(synch);
P2:
wait(synch);
S2;
typedef struct{
int value;
struct process *list;
} semaphore;
wait(semaphore *S) {
S->value--;
if (S->value < 0) {
add this process to S->list;
block();
}
}
signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
remove a process P from S->list;
wakeup(P);
}
}
monitor monitor-name
{
// shared variable declarations
procedure P1 (…) { …. }
procedure Pn (…) {……}
Initialization code (…) { … }
}
}
condition x, y;
Two operations on a condition variable:
If process P invokes x.signal (), with Q in x.wait () state, then Q is resumed, P must wait
Options include
Both have pros and cons – language implementer can decide
Monitors implemented in Concurrent Pascal compromise P executing signal immediately leaves the monitor, Q is resumed
Each procedure F will be replaced by
wait(mutex);
…
body of F;
…
if (next_count > 0)
signal(next)
else
signal(mutex);
semaphore x_sem; // (initially = 0)
int x_count = 0;
x-count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x_sem);
x-count--;
if (x-count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
monitor ResourceAllocator
{
boolean busy;
condition x;
void acquire(int time) {
if (busy)
x.wait(time);
busy = TRUE;
}
void release() {
busy = FALSE;
x.signal();
}
initialization code() {
busy = FALSE;
}
}
A data set is shared among a number of concurrent processes
Problem – allow multiple readers to read at the same time Only one single writer can access the shared data at the same time
Shared data:
writer
do {
wait(rw mutex);
...
/* writing is performed */
...
signal(rw mutex);
} while (true)
reader
do {
wait(mutex);
read count++;
if (read count == 1)
wait(rw mutex); signal(mutex);
...
/* reading is performed */
... wait(mutex);
read count--;
if (read count == 0)
signal(rw mutex); signal(mutex);
} while (true);
structure of philosopher i
do {
wait ( chopstick[i] );
wait ( chopStick[ (i + 1) % 5] );
// eat
signal ( chopstick[i] );
signal (chopstick[ (i + 1) % 5] );
// think
} while (TRUE);
monitor DiningPhilosophers
{
enum { THINKING; HUNGRY, EATING) state [5] ;
condition self [5];
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self [i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
void test (int i) {
if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
出率高
S0: producer execute register1 = counter {register1 = 5}
S1: producer execute register1 = register1 + 1 {register1 = 6}
S2: consumer execute register2 = counter {register2 = 5}
S3: consumer execute register2 = register2 – 1 {register2 = 4}
S4: producer execute counter = register1 {counter = 6 }
S5: consumer execute counter = register2 {counter = 4}
出率高
while (true) {
flag[i] = true;
turn = j;
while (flag[j] && turn == j);
"critical section"
flag[i] = false;
"remainder section"
}
boolean test_and_set (boolean *target)
{
boolean rv = *target;
*target = TRUE;
return rv:
}
do {
waiting[i] = true;
key = true;
while (waiting[i] && key) key = test_and_set(&lock);
waiting[i] = false;
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j]) j = (j + 1) % n;
if (j == i)
lock = false;
else
waiting[j] = false;
/* remainder section */
} while (true);
do{
while (compare_and_swap(&lock, 0, 1) != 0);
/* do nothing */
/* critical section */
lock = 0;
/* remainder section */
}
while (true);
acquire() {
while (!available)
; /* busy wait */
available = false;;
}
release() {
available = true;
}
do {
acquire lock
critical section
release lock
remainder section
} while (true);
writer
do {
wait(rw mutex);
...
/* writing is performed */
...
signal(rw mutex);
} while (true)
reader
do {
wait(mutex);
read count++;
if (read count == 1) wait(rw mutex);
signal(mutex);
...
/* reading is performed */
...
wait(mutex);
read count--;
if (read count == 0)signal(rw mutex);
signal(mutex);
} while (true);
monitor DiningPhilosophers
{
enum { THINKING; HUNGRY, EATING) state [5] ;
condition self [5];
void pickup (int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING) self [i].wait;
}
void putdown (int i) {
state[i] = THINKING;
// test left and right neighbors
test((i + 4) % 5);
test((i + 1) % 5);
}
void test (int i) {
if ( (state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING) ) {
state[i] = EATING ;
self[i].signal () ;
}
}
initialization_code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
Operating System
CSnote