Jon said:
Helge Jensen <helge.jensen@slog.dk> wrote:
You're still relying on double-checked locking, which doesn't work in
.NET without extra volatility. In the above, I don't believe there's
anything to stop the JIT from reordering things such that the new entry
in the hashtable becomes visible before all the writes in the
AzManStore constructor have finished executing.
BTW: the reason I posted the solution was to present the
"canonical-object" as opposed to the "singleton".
Secondly, I'm very interested in the actual problem in the code. The
code is almost identical to production-code I have written. So I am very
interested in knowing exactly what is wrong with it!
I'm not really _sure_ what's the problem. Is it the check outside the lock?
// Registry is monotonic, so we can use any existing
// entry if there is one... without synchronization
if ( existing.ContainsKey(applicationName) )
return existing[applicationName];
I can see the issue, if the impl. of "existing[object item] { set }",
changes the representation of "existing" in a way that makes a
concurrent "existing[object item] { get }" either: diverge, throw, or
(very inlikely) return true.
Is this the problem? I don't think it's a problem with
System.Collections.Hashtable though. (It's not a problem that would
occur in my own Hashtable implementation, due to care in the way the
underlying datastructure is updated
Or is it that the AzManStore constructor inside the lock can be moved
outside the lock and executed before the lock, effectively doing:
AzManStore _moved_outside_lock = new AzManStore(applicationName);
if ( existing.ContainsKey(applicationName) )
return existing[applicationName];
lock (existing.SyncRoot) {
// we need to recheck existance inside the critical region
if ( !existing.ContainsKey(applicationName) )
existing[applicationName] = _moved_outside_lock;
return (AzManStore)existing[applicationName];
}
Which would seem pretty odd to me...
Best guess (from your explanation as I read it, I may be wrong) is that
the AzManStore-construtor would not have been completely evaluated
before invoking "existing[applicationName] { set }" on the new object.
But in that case locking wouldn't help at all, at least from what I can
reason.
or is it something even more exotic?
I would really appreciate an exact description, or reference to an
article, which would make it possible for me to understand and avoid
this problem .