Monday, March 26, 2012

Mutex + Javascript in AJAX rtm?

Hello all -

Would be nice to see mutex implemented natively in AJAX before RTM. Personally I think a lot of poll/update style applications would greatly benefit from this being included directly in the Client FX as I do not see most developers going out of their way to implement this own their own. Here's a nice article on the matter. http://www.developer.com/lang/jscript/article.php/3592016

PS: Are javascript apps getting way too complex? I don't know if I like the words mutex and javascript used in the same sentence.

PPS: Sorry for posting in two forums but networking forum doesn't get much attention.

AO

IMHO, we don't need mutexes in JavaScript, and while the article you link is very interesting, I find it conceptually broken, because JS is not an OO language, neither it is concurrent.

JS is rather "event-driven", and one should know about the timing issues involved, and how these can be solved with a simple flag, rather than writing 10000 lines of (client-side) code to queue what's already queued by the runtime.

To be true, I do not like this very new trend about making OO frameworks out of JS at all, including the design underlying the Asp.Net Ajax framework itself. That is, frameworks where the few is functionality, the most is wrapping a language from its natural paradigm to a foreign one. For this, I would link an article from one of the fathers of the JS language:

JavaScript: The Wrrrld's Most Misunderstood Programming Language

Hope this helps. -LV


Julio - I totally agree with you but the fact remains that browser's do not implement the JS spec faithfully. If you do some testing on different browsers you will find that functions can be called in parallel. Try testing an alert function call (that blocks until it returns) and using an HTR object, you will find that the functions are started in parallel. In my opinion I would sleep more comfortably if I didn't have to implement language hacks such as mutex in Javascript but it seems to me that while we're interacting with native JS objects the single thread paradigm is kept but once we start interacting with browser objects then all bets are off. I realize mutex won't be required in most scenarios but in a few I think they may be necessary...

As for your event-driven comment I am not sure what you mean by a simple flag, maybe you can elaborate? What I think you mean is while(isProcessing) { a = a + 1; }? This would eat up 100% cpu... and is essentially the bakery algorithm that is used in the linked implementation.

Has anyone else experimented with this?


aosipov:

Julio - I totally agree with you but the fact remains that browser's do not implement the JS spec faithfully.

I am too used to work around browsers limitations since the Web has born. That has never required writing 10000 lines of code for - what?

aosipov:

If you do some testing on different browsers you will find that functions can be called in parallel. Try testing an alert function call (that blocks until it returns) and using an HTR object, you will find that the functions are started in parallel.

AFAIK, this is simply not the case. When you callalert, you force the browser to play all events in the queue, in order to synchronize the interface. That's known and documented behavior that all the browsers I am aware of do implement. And, it still is NOT concurrent: events get fired in sequence! That's why a flag ("a boolean value") is enough: there simply is NO concurrency in JavaScript.

This said, I'd be glad to see a practical sample reproducing this "problem", given that not even the author of the mentioned article has provided one...

-LV


For reference, I'll give a sample about where a timing issue can occur and how easy it is to prevent any problem in idiomatic JS.

The full source is here:http://forums.asp.net/ShowPost.aspx?PostID=1456947

Once you have got what that does, just focus on this simple fragment:

// Keep order!
fileDsp.innerHTML = "<em>Loading...</em>";

fileImg.src = fileBox.value;
//

Since this code is loading a local file*, assigning to the src property of the image immediately triggers the onload event for the image. But assigning to the innerHTML property too enqueues an interface update. Bottom line, if you revert the order of the statements above, you do not get correct results, because the sequence in which you enqueue events is the sequence in which they get then run!!!

And, this is true for JS in web pages as well as it is true for any ECMA-based language, like it was JS in VRML, like it is AS in Flash, and so on.

I hope this can shed a bit more light, anyway if you guys have any significant sample that you would like to see analyzed and refactored to "true" JS, please don't be shy and post it. IMHO, it might be a very instructive "case-study" for everybody trying to find their way with client-side programming.

-LV

*If the file was not local, the timing issue involvedmightnot show up. Yet, that is the way to go in general, for robust JS programming... We don't need mutexes, neither we miss OO-JS. We better simply know our language...


Oh yeah: BTW, thefileRefvariable you can see there is a perfect instance of the "flags" I was talking about above.

-LV


Hi again LV - I am glad someone is interested in figuring this out with me.

Here's a simple example where I think a Mutex implementation may be necessary. Create the following page and then launch in IE (make sure to allow popups and not using tabs for new windows!).

<html><head><title>My test page</title></head><body><script type="text/javascript">var o = window.opener;function changeParentValueInParallel() { if (o && !o.closed) { o.changeValue('b'); alert('Parent property changed'); }}window.MyProperty = 'a';if (!(o && !o.closed)) { window.changeValue = function(v) { window.MyProperty = v; } window.open(window.location); alert('Stage pre change parent window.MyProperty: ' + window.MyProperty + '\n\n' + 'Before clicking OK press the Click me button in the child window'); alert('Stage post change parent window.MyProperty: ' + window.MyProperty);}</script><input type="button" name="invoke" onclick="changeParentValueInParallel();" value="Click me"/></body></html>

Here are the steps to reproducing the concurrency. Open the page, then on the parent page there will be an alert - DO NOT CLICK OK, go into the newly opened page (child) and click the button. Then click OK on the parent page. What you will see in IE and Opera (FF behaves in what I consider to be correct behavior) is the parent's window value be changed by the child while I am still in the function. Alas, this is exactly what parallel execution is, and thus the need for mutex (or some other mechanism). I don't think I have to explain how this can damage code, this is fairly standard textbook.

It is my guestimate that the XTR objects and ActiveX behave the same way in IE as well as Opera (does anyone have access to Safari at the moment to test this).

Julio, I am not sure how a simple flag would be able to help here. Would love to know what other ways other than mutex implementation would work here to prevent this sort of thing in critical sections. By the way, the mutex implementation is only 30 lines (not 10,000 as you say).

Everyone, please chime in here this is fairly important (I think).

Alex


aosipov:

Here's a simple example where I think a Mutex implementation may be necessary.

I'm afraid your sample is not very much significant. Apart from the fact that it is quite far from any real life code, the basic problem is that - as said before - in JS the "sequence" of the messages is what matters, and you have actually messed that up, so that it can't but misbehave... you wrote it to do it! (E.g. you call "before" what you are really executing "after", and you try to get results from the same opening method, while you should really do that from the popup *after* the popup has finished...)

aosipov:

By the way, the mutex implementation is only 30 lines (not 10,000 as you say).

10000 stands for far-too-many, and I was talking about the client-side frameworks in general there.

-LV


This was a proof of concept in the most simple example that I could make without adding complexity of a real world application. I have experienced similar problems (concurrency based) in real world applications but I cannot post this code nor would anyone examine it. To get back to the real problem, with asynchronous callbacks I cannot control the sequence of events (at least in IE and Opera) and cannot guaruantee that a function will not run concurrently. This is not a problem for me as my code is already ready for such guaranteeing critical sections and critical data are locked during execution. The point of this post was to get Atlas/AJAX team to recognize that a problem exists and possibly get a generic solution included in AJAX so we don't have to roll out our own custom solutions. This seems to be a general enough problem that a lot of programming languages or standard libraries include mechanisms to work around it and it seems reasonable for AJAX as a client side library to provide a similar mechanism. I could be wrong but I am pretty sure my example shows the fundamental problem (of course not in a real world scenario).

Am I on crazy pills? I would love not to have to resort to such complexity in javascript if someone can explain to me a viable alternative to guarantee my global memory will not be corrupted/modified concurrently. Please help!

Alex


aosipov:

I cannot control the sequence of events (at least in IE and Opera) and cannot guaruantee that a function will not run concurrently.

Not only you can control the sequence of events, but - again - there simply is NO CONCURRENCY in JS.

The basic problem (IMHO) is that you are mixing concepts from other languages completely different from the JS and its runtime model. That's why I am basically only stressing that you should know your language, rather than ask for foreign constructs you are more familiar with. Those constructs simply do not apply here!*

aosipov:

I could be wrong but I am pretty sure my example shows the fundamental problem (of course not in a real world scenario).

The code above is simply wrong. It misbehaves because you have written it so that it cannot but misbehave...

aosipov:

Am I on crazy pills?

Incorrect is not crazy, and I appreciate your efforts to get deeper.

So, now I'll stop and wait with you for more feedback, in case anybody has something to add.

-LV

*With an analogy: var x = "2" + "2" not giving back 4 doesn't imply - say - that JS lacks operator overloading, it would rather imply the programmer doesn't know what (s)he is doing...


LudovicoVan:


Not only you can control the sequence of events, but - again - there simply is NO CONCURRENCY in JS.

What is my example then? Here's a definition out of Wikipedia "Concurrency occurs when two or more execution flows are able to run simultaneously." What am I missing?

LudovicoVan:


The basic problem (IMHO) is that you are mixing concepts from other languages completely different from the JS and its runtime model. That's why I am basically only stressing that you should know your language, rather than ask for foreign constructs you are more familiar with. Those constructs simply do not apply here!


To guarantee atomicity I use a mutex. This is a concept that applies to languages that are able to execute flows simultaneously. Javascript may not be such a language and I am not agruing that it is. The implemention of Javascript in IE and Opera (but NOT FIREFOX) allows for parallel execution and thus arises my need for concurrency control. The IE and Opera javascript runtime model (to use your words) allows for concurrency as demonstrated by my example (I am sure this was a design decision to allow faster rendering). In a perfect world, Javascript would be single threaded and would lock the window global object to updates until the current code is finished executing - this would guarantee a safe environment where no race conditions can occur. This is what Firefox does. To restate again, this is NOT the case in IE and Firefox. Therefore I need to guarantee some of my updates are atomic and therefore I use mutex implementation.

LudovicoVan:


The code above is simply wrong. It misbehaves because you have written it so that it cannot but misbehave...


Like I said previous, this example was a demonstration of concurrency showing the base problem (in the simplest way I could think of). I can repeat the same behavior with asynchronous callbacks, that is I can make a request that calls one of my callback functions in parallel to another function executing. The reason I made this example is because it is much easier to catch because there is no timing involved and I can control the timing myself and preproduce the problem every time, rarther than reproducing the problem under certain circumstances that are hard to simulate in an example (if not impossible w/o extensive retries).

I am not sure how I am incorrect here. LV, I too appreciate your effort to uncover the real needs here!!! I understand your point that javascript doesn't have concurrency but in the real world of browsers we must work around different implementations so I am looking for the best way to do this and possibly get this included in a standard framework (AJAX). This is pretty important.


I think it may appear that there is concurrency when in fact there isn't... when an Alert is open, the browser may divide the code into seperate tasks, and there are situations where other code may run while the original alert is open. But without the alert there could not be any concurrency. Basically using alert to try and prove concurrency isn't going to work. You can get multiple paths through the same code using this trick but only if you introduce an alert -- it cant happen otherwise.
I have seen this same problem w/o using alerts but with XTR callbacks.

aosipov:

What is my example then? Here's a definition out of Wikipedia "Concurrency occurs when two or more execution flows are able to run simultaneously." What am I missing?

JS is not concurrent, that is you never ever have two paths of execution running at the same time in the context of the same host (in our case, a browser's window). What you get is incorrect sequence of execution, not concurrent execution.

aosipov:

Like I said previous, this example was a demonstration of concurrency

Again, it is not concurrent. It just shows a messed-up flow.

aosipov:

I can repeat the same behavior with asynchronous callbacks, that is I can make a request that calls one of my callback functions in parallel to another function executing.

This should simply not be the case, so maybe post a sample...

In the meantime I'll tell you that this approach would mess the flow up:

// Which runs first?
StartHttpRequest(httpCallback);
StartTimer(timerCallback, 2000);
function httpCallback() { doSomethingFirst(); }
function timerCallback() { doSomethingAfter(); }

This approach instead would work reliably:

StartHttpRequest(httpCallback);
function httpCallback() { doSomethingFirst(); doSomethingAfter(); }

There is no concurrency, it is a matter of "sequence". -LV


Hello back, here is maybe a more significant example.

Say we have to issue two server calls returning an integer, then get the sum of the two integers and use that in a third function. We are not guaranteed the order of execution for the two callbacks, neither we actually know when they are going to return a value at all. How we could "architect" this? Here is some code, not perfect because it still is a generic sample, so no point in "optimizing", yet should give some hints:

var cbCount, cbValue1, cbValue2;

// Whatever the timing, these two callbacks
// won't run concurrently, so no need
// for a synchronization mechanism
function httpCallback1(v) {
cbValue1 = parseInt(v, 10);
if(++cbCount == 2) finishProcess();
}
function httpCallback2(v) {
cbValue2 = parseInt(v, 10);
if(++cbCount == 2) finishProcess();
}

function startProcess() {
cbCount = 0;
startHttpReq1(httpCallback1);
startHttpReq2(httpCallback2);
}

function finishProcess() {
var sum = cbValue1 + cbValue2;
alert(sum);
}

startProcess();

A bit improperly, anyway here we might think of the cbCount as a "semaphore".

Hope this can shed more light. (Does it?) -LV

No comments:

Post a Comment