Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript thread-handling and race-conditions

Lets asume I have a code like the following:

var shared = 100;
function workWithIt(){
    shared += 100;
}

setTimeout(workWithIt, 500);
setTimeout(workWithIt, 500);

Ideally, this piece of code should add 200 to the variable shared, which is 300 afterwards.

But, as I know from c, there can be some implications, if the operation += is split into multiple commands.

Lets say, that this is the execution-order of the function:

setTimeout() --> create Thread A
setTimeout() --> create Thread B
wait 500ms

      **Thread A**              |        **Thread B**
--------------------------------+---------------------------------
var tmpA = shared;  //100       |
                                |   var tmpB = shared; //100
                                |   tmpB = tmpB+100;   //tmpB=200
                                |   shared = tmpB;
tmpA = tmpA+100;    //tmpA=200  |
shared = tmpA;                  |

In this case, shared has now the value 200.

This can happen in many programming-languages like c, c++, java, c#, ... - but can it also happen in Javascript?

Or more generally speaking: How does Javascript handle its threads, when does it switch between threads, and are there built-in methods, that can be used for handling race-conditions?

like image 283
maja Avatar asked Jan 30 '14 21:01

maja


People also ask

Are there race conditions in Javascript?

Yes, race conditions can and do occur in JS as well. Just because it is single-threaded it doesn't mean race conditions can't happen (although they are rarer).

How do you handle race condition in multithreading?

an easy way to fix "check and act" race conditions is to synchronized keyword and enforce locking which will make this operation atomic and guarantees that block or method will only be executed by one thread and result of the operation will be visible to all threads once synchronized blocks completed or thread exited ...

What is race condition in threading?

A race condition occurs when two threads access a shared variable at the same time. The first thread reads the variable, and the second thread reads the same value from the variable.

How can race conditions be prevented in threading?

To avoid race conditions, any operation on a shared resource – that is, on a resource that can be shared between threads – must be executed atomically. One way to achieve atomicity is by using critical sections — mutually exclusive parts of the program.


2 Answers

JavaScript code has a single explicit thread of execution. The scenario you've described will never take place in JavaScript. A timer callback is just another kind of event, and all events are serialized for sequential execution by the same core event loop of the browser UI thread.

Thus, two timer events cannot be processed concurrently, one callback will happen after another.

You still can have real concurrency in JavaScript by means of Web Workers. However, a web worker cannot share any objects with another web worker or the main thread. Instead, web workers serialize their state objects with JSON, and exchange messages with postMessage. So, your scenario is still impossible.

However, consider another case:

var shared = 100;

function workWithIt1(){
    shared += 100;
}

function workWithIt2(){
    shared = shared/2;
}

setTimeout(workWithIt1, 500);
setTimeout(workWithIt2, 500);

Will shared be 150 or 100, once both timeouts have been fired? It probably will be 100, because the workWithIt1 timeout was queued first. However, I would not rely upon this fact though, because both timers have the same timeout value of 500, and implementation of timers might be browser-specific. You may want to avoid side effects like that in your code.

like image 151
noseratio Avatar answered Oct 27 '22 01:10

noseratio


AFAIK, there is no multithreading in JS. I changed your example a bit to try to understand what you mean.

var shared = 100;
function workWithIt(a){
    shared += a||100;
    console.log(shared);
}

setTimeout(function(){workWithIt(5);}, 500);
setTimeout(function(){workWithIt(10);}, 500);
console.log(shared);

With this code, the result is always (in my testing):

100
105
110

This indicates to me that there is no chaotic or random or even interesting process here. There are certain possibilities to create racing conditions with JS in the browser, but your timing example is not that. Racing requires only a breakdown in predictability of execution order. Maybe if you change your delay from 500 to Math.floor(500 * Math.random()) you would have a racing condition.

like image 35
Femi Avatar answered Oct 27 '22 00:10

Femi