we sometimes need to know the thing that we wanted to happen happened.
used to solely to block tasks to wait up for synchronization.
The weakest form of blocking lock as its only state is list of blocked tasks.
also called condition lock.
The simplest form - it relies the caller to lock it for you from the outside.
class SyncLock{
Task *list;
public:
SyncLock() : list(nullptr){}
void acquire(){
// ass self to task list
yieldNoSchedule();
}
void release(){
if( list != nullptr){
// remove task from blocked list and make ready
}
}
};
This sync lock does not have spin/blocking lock! so it requires mutex outside from the class, before it's usage.
MutexLock m;
SyncLock s(m);
bool occupied = false;
// acquiring task
m.acquire();
if(occupied){
s.acquire(m);
// acquire releases m for you.
// <<<there may be preemption here too
m.acquire();
}
occupied = true;
m.release();
// barging prevention
m.acquire();
if(!s.empty()) s.release();
else{occupied = false; m.release();}
Internal locking.
class SyncLock{
Task *list;
SpinLock lock;
public:
SyncLock() : list(nullptr){}
void acquire(MutexLock &m){
lock.acquire();
// ass self to task list
m.release();
//CAN BE INTERRUPTED HERE
yieldNoSchedule(lock);
m.acquire();
}
void release(){
lock.acquire()
if( list != nullptr){
// remove task from blocked list and make ready
}
lock.release();
}
};
class uCondLock{
public:
uCondLock();
void wait(uOwnerLock & lock);
bool signal();
bool broadcast();
bool empty();
}
use of sync lock is complicated because they are weak.
// waiting part
m.acquire();
if(!done) c.wait(m); // global flag
m.release();
S2;
// signal part
S1;
m.acquire();
done = true;
c.signal();
m.release();
Bounded buffer question