Semaphore simulation

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…

I had to deal with similar challenges. I wasn’t familiar with promises and the promise .nut wasn’t yet written so I did it with queues. I have a very simple queue class with methods like enqueue (add to end), dequeue (take from front) and notEmpty (true or false) and use a semaphore and the queue to manage everything. Works fine. Here is some drastically simplified code:

`    _queue = queue()
    _busy = false

    function write(data,callback){
            if (!_busy) {
                _busy=true
                eepromWrite(data,function(resp){
                    _busy=false
                    if (_queue.notEmpty())
                        write.acall(_queue.dequeue())
                    callback(resp)
                }.bindenv(this))
            }
            else
                _queue.enqueue([this,data,callback])
    }`

interesting… I had a similar approach with queues, but a generator driven mechanism to to dequeue. After some difficult to catch issues with the queue mgt locking up I ditched it and looked for something else.

Interesting line in the approach above is the write.acall(…) . I have a feeling that this is what I needed when I went for the (problematic) generators… Need to take a closer look.