I needed a way of ‘protecting’ resources in a multi threaded environment that are accessed asynchronously (because they take time to return a result) and can have many consumers but can handle only one simultaneously (eg EEPROM)
Similar to binary Semaphore behaviour in an pre-emptive RTOS.
I found a way by use of Promises that actually does exacty that (Promises are difficult to grasp at first, but unbelievable powerfull - THANKS FOR THE LIBRARY!!!), but it’s rather complex.
`
#require “promise.class.nut:3.0.0”
busy <- false;
function SemaphorePromise()
{
local Cnt = 0;
if (!busy) {// if resource not busy, do our thing immediately
return Promise(function(resolve,reject) {
resolve(“Immediate resolution as not busy when invoked”);
}.bindenv(this));
} // else get into a loop trying again until not busy…
return Promise.loop(
@() busy == true,
function(){
//server.log(“Looping”);
return Promise(function(resolve,reject) {
imp.wakeup(1,function() {
Cnt++;
if (!busy) {
resolve("Delayed resolution with Cnt : " + Cnt);
}
else {
resolve(“still busy”); // note : this will never be the final resolution…
}
}.bindenv(this));
}.bindenv(this));
}.bindenv(this));
}
// test invokation and busy manipulation code
busy = true;
imp.wakeup(10,function(){
server.log(“Setting Busy = false”)
busy = false;});
SemaphorePromise()
.then(function(result) {
server.log(result);
});
`
The places where resolve() is called can be replaced by whatever complex asynchronous piece of code (eg Bullwinkle send from agent to the device), as long as it resolves in the end…the busy flag may well be set/reset inside these blocks instead of separately as done in this test code.
Question : although it’s working fine, is there a simpler way ? Eg, is there a way to have the Promise.loop execute at least once when the condition is false from the start (which is the only reason why lines 2-5 are there) ?
PS sorry for the formatting. Code block doesn’t seem to handle pasting of tabs well…