synchronized (this[.classinfo]) in druntime and phobos
Steven Schveighoffer
schveiguy at yahoo.com
Wed May 30 08:50:37 PDT 2012
On Mon, 28 May 2012 18:36:13 -0400, Alex Rønne Petersen <alex at lycus.org>
wrote:
> Hi,
>
> I've seen several occurrences of synchronized (this) and synchronized
> (this.classinfo) in both druntime and phobos by now. I propose that we
> officially ban these patterns with extreme prejudice.
>
> 1) Locking on the object instance is a HORRIBLE IDEA. Anyone who happens
> to use the object for locking will most likely end up with a deadlock on
> their hands.
> 2) Locking on something as fundamental as type info means that any
> arbitrary part of the application could cause a deadlock by doing the
> same.
Reading all of this thread, I think I agree with you.
Now, I'll point out a couple things:
1. Most code that is written with synchronized is *not* abused.
2. using synchronized(x) should not go away.
Here is what I'm thinking:
First, we give control of the mutex to the author of the type. So instead
of an implicit location, and implicit lazy construction, we make
everything explicit:
Currently:
synchronized(x)
{
}
translates to
if(x.mutex == null)
x.mutex = createmutex();
lock(x.mutex)
try
{
}
finally
{
unlock(x.mutex);
}
So I propose it does this instead (entirely via lowering):
synchronized(x)
{
}
translates to:
auto l = x.__getMutex();
l.lock();
try
{
}
finally
{
l.unlock();
}
So we have a few benefits here:
1. if typeof(x) does not define __getMutex, the above is a compiler error.
2. We can control the visibility of the mutex, because we can attribute
private or protected to the __getMutex function.
3. We can control what kinds of objects of typeof(x) use mutexes. e.g.
define __getMutex() shared only.
4. We have control over the type of the lock, it can be anything and does
not need to fit into some runtime function's interface.
Second, I propose a somewhat gradual transition. I think on first
release, we *still* keep the allocated word in the class instance, and
keep the druntime function which lazily allocates the mutex. Therefore,
changing an object that currently *properly* can use synchronized(this)
can be made to work:
class Synchronizable
{
xxx __getMutex() shared { return _d_getObjectMonitor(this);}
}
We can deprecate that functionality, and the allocated space for the mutex
later if desired.
-Steve
More information about the Digitalmars-d
mailing list