_Task Worker {
Intent * intents;
int N, priority, i, j;
void main() {
for ( i = 1; i <= 1000; i += 1 ) {
// step 1, wait for threads with higher priority
do { // entry protocol
intents[priority] = WantIn;
// check if thread with higher priority wants in
for ( j = priority - 1; j >= 0; j -= 1 ) {
if ( intents[j] == WantIn ) {
intents[priority] = DontWantIn;
while ( intents[j] == WantIn ) {}
break;
} // exit
}
} while ( intents[priority] == DontWantIn );
// step 2, wait for threads with lower priority
for ( j = priority + 1; j < N; j += 1 ) {
while ( intents[j] == WantIn ) {}
}
CriticalSection(); // critical section
intents[priority] = DontWantIn; // exit protocol
}
}
public:
Worker( Intent intents[ ], int N, int priority ) :
intents( intents ), N(N), priority( priority ) {}
};
int main() {
const int NoOfTasks = 10;
Intent intents[NoOfTasks]; // shared
Worker *workers[NoOfTasks];
for ( int i = 0; i < NoOfTasks; i += 1 ) { // initialize shared data
intents[i] = DontWantIn;
}
for ( int i = 0; i < NoOfTasks; i += 1 ) {
workers[i] = new Worker( intents, NoOfTasks, i ); // create workers
}
for ( int i = 0; i < NoOfTasks; i += 1 ) { // terminate workers
delete workers[i];
}
}
thread with n priority will first scan higher priority boards for any intent/usage of CS,
then looks for intent/usage of lower priorities.
for N threads, make N/2 pairs and put them all under Dekker's algorithm in reversed tree path.
create a full-time arbitrator task to control entry to CS.
There is an Arbiter that looks for intents, and chooses a intent to enter CS.
This is not mutual exclusion!
This is syncronization!
Difference
mutual exclusion is not allowing two threads to enter CS at the same time.
syncronization is setting order for threads. more costly.
Cheat in order and speed of execution!
It simplifies the problem.
make a special instructions to perform an atomic read+write operation
int Lock = OPEN //shared
int TestSet(int &b){
//begin atomic
int temp = b;
b = CLOSED;
// end atomic
return temp;
}
void Task::main(){
while(TestSet(Lock) == CLOSED);
// CS
Lock = OPEN;
}
This only works for a single CPU.
To make this work, hardware needs to be implemented so that if Lock is locked, it actually blocks(stall) other CPU.
Atomic swap
int Lock = OPEN
void Swap(int &a, &b){
int temp;
// begin atomic
temp = a;
a = b;
b = temp;
// end atomic
}
void Task::main(){
int dummy = CLOSED;
do{
Swap(Lock, dummy);
}while(dummy == CLOSED);
// CS
Lock = open
}
it does not a read and a write atomically, it does two reads and two writes atomically.
Spin lock busy waits burning massive amount of CPU time.
What we want to do is to do is to go sleep while waiting.
uLock{
void acquire();
void release();
}
uLock lock(/* 0 - locked, 1 - opened */)