views:

4482

answers:

3

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?

A: 

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

good luck

PERR0_HUNTER
+6  A: 

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.

olliej
I added the full code above to make it a bit more clear. The engine is Webkit (safari). From javascript I invoke external processes, and the external process invokes the "done" method when it's done. Basically I need to make sure only one external process runs at a time.
Parand
Assuming you're doing something similar to [someObject call] or JSObjectCallAsFunction(context, doneFunction, someObject), you should make sure that you are calling on the main thread, especially if you're using the ObjC JS API provided by WebKit (IIRC it may circumvent some of the locks)
olliej
Have you used the webkit sdk on the iPhone by any chance? I'm using a simple window.location scheme, haven't tried the SDK. Would love to learn more about the SDK.
Parand
Nope, i know very little about the iPhone SDK -- I only know JSC's C api :D
olliej
+3  A: 

A quick Google search for "javascript mutex" returned this article (Implementing Mutual Exclusion in JavaScript).

codelogic