On Sep 9, 2009, at 6:33 PM, Jeremy Orlow wrote:
In general this seems like a pretty interesting idea. It definitely
would be nice to completely abstract away all concepts of
concurrency from web developers, but some of our solutions thus far
(message passing, async interfaces, etc) have not been terribly
appreciated by developers either. The GlobalScript proposal is a
good example: to us, shared workers were an adequate solution, but
in practice the lack of shared state is very difficult for some
developers to work around. Possibly even more difficult than
dealing with some levels of concurrency.
I think it'd be interesting to introduce this as an experimental API
and see what web developers do with it.
I think it's predictable that it will be used in badly wrong ways
without implementing it. Explicit application-managed locking is a
massive failure as a mechanism for managing concurrency.
As for the idea of a sync API: What if some library/framework and
the embedding page use these flags/locks? I know you can't actually
deadlock with this API, but I worry some developers will just do |
while(!acquireLock("flag")) {}| which could lead to deadlocks. Only
allowing an async API would fix this, but developers have typically
not liked async APIs.
If we want to go async, then I'd rather have an asynchronous way to
acquire an *actual* lock on the resource (as with the LocalStorage
async transaction proposal), than an async advisory locking model.
Having both asynchronicity *and* advisory locks seems like the worst
of both worlds.
On the other hand, if we offer only the equivalent of tryLock() and
not a blocking lock(), it's almost certain Web apps will build spin
locks in the way you describe, leading to wasteful CPU usage, bad
performance, and the possibility of deadlocks.
Here's another idea that I think is actually kind of cool: What if
we kept track of locking precedence (i.e. the graph of which locks
have been taken while other locks were held) and threw an exception
if any lock was ever taken in a way that violated the graph. In
other words, we wouldn't make the developer tell us the locking
precedence, and we wouldn't wait until you hit an actual deadlock.
Instead we would look for the first call site that _could_ have
deadlocked. A long time ago, I was working on a project that had
some deadlock problems. We implemented exactly this and it worked
pretty well.
This seems like a very challenging programming model for little gain.
If the locks are purely advisory, they do not prevent race conditions,
but a discipline to prevent deadlocks will still make them very hard
to use. Note also that the possibility of synchronous cross-site code
execution would require a lock precedence graph to be cross-site to
really prevent deadlocks, but it would be impossible for a Web
application to guarantee anything about lock order with respect to Web
apps in different origins. The other possibility is to drop all locks
in the case of synchronous cross-origin code execution, but then these
advisory locks would not even be useful for preventing race conditions.
Locking is broken - just don't do it.
Regards,
Maciej
On Thu, Sep 10, 2009 at 9:22 AM, Olli Pettay
<[email protected]> wrote:
On 9/10/09 2:24 AM, Robert O'Callahan wrote:
On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher <[email protected]
<mailto:[email protected]>> wrote:
Yes, exactly. Sorry for not making this clear. I believe implicit
locking for LocalStorage (and the implicit unlocking) is going to
yield something very confusing and hard to implement well. The
potential for dead locks when you fail to implicitly unlock
properly
scares me
You mean when the browser implementation has a bug and fails to
implicitly unlock?
Giving Web authors the crappy race-prone and deadlock-prone locking
programming model scares *me*. Yes, your acquireLock can't get you
into
a hard deadlock, strictly speaking, but you can still effectively
deadlock your application by waiting for a lock to become available
that
never can. Also, how many authors will forget to test the result of
acquireLock (because they're used to other locking APIs that block)
and
find that things are OK in their testing?
If you're concerned about that, make acquireLock to throw an
exception.
Authors sure will notice that things aren't quite right, if the flag
isn't acquired.
And if the acquireLock("flag", callback) approach is used, it is
harder to make the mistake to not check whether the flag was really
got.
This seems like a good idea.
As you said on IRC, perhaps there should be a way to acquire
many flags at once and then call the callback.
I like this idea as well.