Javascript semaphore / test-and-set / lock?
Is there such a thing as an atomic test-and-set, semaphore, or lock in Javascript?
I have javascript invoking async background processes via a custom protocol (the background process literally runs in a separate process, unrelated to the browser). I believe I'm running into a race condition; the background process returns between my test and my set, screwing things up on the javascript side. I need a test-and-set operation to make it a real semaphore.
Here's the javascript code that attempts to detect background processes and queue them up:
Call = function () {
var isRunning = true,
queue = [];
return {
// myPublicProperty: "something",
call: function (method) {
if (isRunning) {
console.log("Busy, pushing " + method);
queue.push(method);
} else {
isRunning = true;
objccall(method);
}
},
done: function() {
isRunning = false;
if (queue.length > 0) {
Call.call(queue.shift());
}
}
};
}();
Call is a singleton that implements the queuing; anybody that wants to invoke an external process does Call.call("something") .
Any ideas?
JavaScript has no locking semantics because JS is not a multi threaded language. Multiple threads can only operate concurrently in completely distinct contexts -- eg. HTML5 Worker threads, or in things like multiple instances of JavaScriptCore API's context object (I assume SpiderMonkey has a similar concept). They can't have shared state, so in essence all execution is atomic.
Okay, as you have now provided some of your code i assume you have something akin to:
External Process:
<JSObject>.isRunning = true;
doSomething()
<JSObject>.done()
Or some such (using appropriate APIs). In which case I would expect the JS engine to block if JS is executing in the context of your js object (which is what JavaScriptCore would do), failing that you will probably need to put a manual lock in place around js execution.
What engine are you using to do all of this? I ask because based on your description it sounds like you're setting a flag from a secondary thread from a non-JS language using the C/C++ API provided by that language, and most JS engines assume that any state manipulation made via the API will be occurring on a single thread, typically the same thread that all execution occurs on.
First of all, while it is true that javaScript is single threaded, it is NOT true that no serialization mechanism is ever required by a javaScript application.
A simple example, is when a submit button should fade out for a set amount of time during which an Ajax request to a server is working. When the asynchronous Ajax request successfully completes then a message should appear where the button used to be.
While it would be nice to be able to cancel the button's fadeout and simply set its style to "display: none", as soon as the Ajax request completes, that is not possible in jQuery. Also, a solution could use Events to synchronize the two simultaneous activities, but that is essentially overkill for a simple problem.
A low-tech solution is to poll a lock and when the fadeout completes it is unlocked but the "server done" message is NOT displayed until the success callback, as set by $.post, executes.
var gl_lock;
var gl_selfID;
function poll_lock(message) {
if (gl_lock === 0) {
$('#output').text(message).fadeIn(200);
window.clearInterval(gl_selfID);
}
} // end of poll_lock
function worker() {
// no one gets in or out
gl_lock = 1;
$.post(..., data,function() {
gl_selfID = window.setInterval(poll_lock, 40, data.message);
}, "json");
// end of fadeout unlock the semaphore
$('#submit-button').fadeOut(400, function() { gl_lock = 0; });
} // end of worker
Finally, I think this is more detailed answer, along the lines previously suggested in this discussion by perrohunter.
Maybe you could implement a basic integer semaphore, just add the variable into the DOM and lock/unlock it and make sure your functions keep checking it, else timeout them =)
If you are using a framework such as Mootools you could try to handle the flow of the app with events such as onComplete and so on.