Statically allocated storage within a module is accessible to all the functions of that module, and there is no explicit mechanism in Limbo for synchronizing concurrent updates to this storage from several tasks. However, it is straightforward to build a variety of concurrency-control mechanisms by using channel communications.
An example is a module that implements a Monitor abstract data type. Each instance of Monitor has a lock and an unlock operation; calling lock delays if another task holds the lock; calling unlock releases the lock and enables any other task attempting to execute lock.
implement Mon;
Mon: module
{
Monitor: adt {
create: fn(): Monitor;
lock: fn(m: self Monitor);
unlock: fn(m: self Monitor);
ch: chan of int;
};
};
Monitor.create(): Monitor
{
m := Monitor(chan of int);
spawn lockproc(m.ch);
return m;
}
Monitor.lock(m: self Monitor)
{
m.ch <- = 0;
}
Monitor.unlock(m: self Monitor)
{
<- m.ch;
}
lockproc(ch: chan of int)
{
for (;;) {
<- ch; # wait for someone to lock
ch <- = 0; # wait for someone to unlock
}
}
mp: Mon; Monitor: import mp; mp = load Mon "..."; l := Monitor.create(); . . . l.lock(); # region of code to be protected; # only one thread can execute here at once. l.unlock();