118

I have seen this link: Implementing Mutual Exclusion in JavaScript. On the other hand, I have read that there are no threads in javascript, but what exactly does that mean?

When events occur, where in the code can they interrupt?

And if there are no threads in JS, do I need to use mutexes in JS or not?

Specifically, I am wondering about the effects of using functions called by setTimeout() and XmlHttpRequest's onreadystatechange on globally accessible variables.

Ovesh
  • 5,209
  • 11
  • 53
  • 73

7 Answers7

115

Javascript is defined as a reentrant language which means there is no threading exposed to the user, there may be threads in the implementation. Functions like setTimeout() and asynchronous callbacks need to wait for the script engine to sleep before they're able to run.

That means that everything that happens in an event must be finished before the next event will be processed.

That being said, you may need a mutex if your code does something where it expects a value not to change between when the asynchronous event was fired and when the callback was called.

For example if you have a data structure where you click one button and it sends an XmlHttpRequest which calls a callback the changes the data structure in a destructive way, and you have another button that changes the same data structure directly, between when the event was fired and when the call back was executed the user could have clicked and updated the data structure before the callback which could then lose the value.

While you could create a race condition like that it's very easy to prevent that in your code since each function will be atomic. It would be a lot of work and take some odd coding patterns to create the race condition in fact.

William
  • 6,338
  • 4
  • 32
  • 36
  • 35
    It's not hard at all to create this race condition: for instance, I have a "onkeyup" event in a field, that triggers an ajax call to a DB to get some values. Quickly typing data can easily lead to out-of-order results. – thomasb Nov 17 '17 at 16:15
23

The answers to this question are a bit outdated though correct at the time they were given. And still correct if looking at a client-side javascript application that does NOT use webworkers.

Articles on web-workers:
multithreading in javascript using webworkers
Mozilla on webworkers

This clearly shows that javascript via web-workers has multithreading capabilities. As concerning to the question are mutexes needed in javascript? I am unsure of this. But this stackoverflow post seems relevant:
Mutual Exclusion for N Asynchronous Threads

Community
  • 1
  • 1
gorillatron
  • 419
  • 4
  • 5
  • 5
    blast from the past, but i encountered the need for mutexes when multiple tabs access the same local storage – psp May 15 '14 at 13:46
  • 3
    WebWorkers don't affect re-entrancy because they share no variable state and only communicate with the main thread by passing messages, which trigger events. – Alnitak Aug 01 '14 at 11:05
  • And this needs more updates… there’s [`SharedArrayBuffer`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer). – Sebastian Simon Nov 26 '22 at 17:04
10

Yes, mutexes can be required in Javascript when accessing resources that are shared between tabs/windows, like localStorage.

For example, if a user has two tabs open, simple code like the following is unsafe:

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

Between the time that the localStorage item is 'get' (accessors) and 'set' (mutators), another tab could have modified the value. It's generally unlikely, but possible - you'd need to judge for yourself the likelihood and risk associated with any contention in your particular circumstances.

See the following articles for a more detail:

Sachintha Udara
  • 635
  • 1
  • 7
  • 22
decates
  • 3,406
  • 1
  • 22
  • 25
7

As @william points out,

you may need a mutex if your code does something where it expects a value not to change between when the asynchronous event was fired and when the callback was called.

This can be generalised further - if your code does something where it expects exclusive control of a resource until an asynchronous request resolves, you may need a mutex.

A simple example is where you have a button that fires an ajax call to create a record in the back end. You might need a bit of code to protect you from trigger happy users clicking away and thereby creating multiple records. there are a number of approaches to this problem (e.g. disable the button, enable on ajax success). You could also use a simple lock:

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

I'm not sure if that's the best approach and I would be interested to see how others handle mutual exclusion in javascript, but as far as i'm aware that's a simple mutex and it is handy.

alzclarke
  • 1,725
  • 2
  • 17
  • 20
  • 6
    I'd hardly call this a mutex, at least not in the traditional sense, because you don't have two threads running in the context of a single block at any time. – Ovesh Jul 20 '11 at 10:59
  • 16
    a mutex is simply an algorithm that helps 'avoid the simultaneous use of a common resource'. Although multithreading creates a need for mutexes, there's nothing in the definition that says a mutex is specific to the situation you describe. – alzclarke Jul 21 '11 at 07:20
  • 2
    You are correct about the formal definition of mutex. But this is hardly what people think about when they talk about mutexes in the real world. – Ovesh Jul 21 '11 at 07:38
  • This is not working as expected. Unfortunately, repeated clicks will still fire the ajax call. Any other idea? – Mohammed Shareef C Jul 21 '17 at 12:02
  • 1
    Pretty sure this should be wrapped in a `while` with `setTimeout` or a `setInterval` with `clearInterval` after n failures so that you have retry & timeout logic. Leaving as-is means you'd just bypass code that is locked. The external handling with mutexes and shared objects is as important as the implementations themselves. – MrMesees Apr 28 '19 at 20:06
  • 2
    Old post, but it seems to me as long as the read operation `if(!save_lock)` and the write `save_lock=true` are not a single atomic operation, then more than one thread will be able to run that block. Needs a "test and set" IMHO. – xdhmoore Sep 23 '20 at 03:26
  • After reading some more I think I was wrong about the atomic operation. Because of js' [run to completion architecture](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Run-to-completion), AFAICT those operations *would* be guaranteed to run together. At least [most of the time](https://stackoverflow.com/a/2734311/356887). – xdhmoore Sep 24 '20 at 01:41
  • Store save_lock in the local storage, and you might have something closer to a mutex, since they are system wide. – Brain2000 Apr 05 '22 at 17:17
  • as @xdhmoore said. That's not an atomic operation. So multi threaded JavaScript like in modern Chrome can hit a function multiple times between the if and the set. I actually had that issue today. – Bucket Jul 17 '23 at 16:04
3

JavaScript is single threaded... though Chrome may be a new beast (I think it is also single threaded, but each tab has it's own JavaScript thread... I haven't looked into it in detail, so don't quote me there).

However, one thing you DO need to worry about is how your JavaScript will handle multiple ajax requests coming back in not the same order you send them. So, all you really need to worry about is make sure your ajax calls are handled in a way that they won't step on eachother's feet if the results come back in a different order than you sent them.

This goes for timeouts too...

When JavaScript grows multithreading, then maybe worry about mutexes and the like....

Mike Stone
  • 44,224
  • 30
  • 113
  • 140
2

JavaScript, the language, can be as multithreaded as you want, but browser embeddings of the javascript engine only runs one callback (onload, onfocus, <script>, etc...) at a time (per tab, presumably). William's suggestion of using a Mutex for changes between registering and receiving a callback should not be taken too literally because of this, as you wouldn't want to block in the intervening callback since the callback that will unlock it will be blocked behind the current callback! (Wow, English sucks for talking about threading.) In this case, you probably want to do something along the lines of redispatching the current event if a flag is set, either literally or with the likes of setTimeout().

If you are using a different embedding of JS, and that executes multiple threads at once, it can get a bit more dicey, but due to the way JS can use callbacks so easily and locks objects on property access explicit locking is not nearly as necessary. However, I would be surprised if an embedding designed for general code (eg, game scripting) that used multi threading didn't also give some explicit locking primitives as well.

Sorry for the wall of text!

Simon Buchan
  • 12,707
  • 2
  • 48
  • 55
-3

Events are signaled, but JavaScript execution is still single-threaded.

My understanding is that when event is signaled the engine stops what it is executing at the moment to run event handler. After the handler is finished, script execution is resumed. If event handler changed some shared variables then resumed code will see these changes appearing "out of the blue".

If you want to "protect" shared data, simple boolean flag should be sufficient.

Constantin
  • 27,478
  • 10
  • 60
  • 79