Proposals: Synchronization
Kent Boogaart
kentcb at internode.on.net
Tue Jul 25 05:29:36 PDT 2006
I feel the need for a more concrete example. Suppose you write this class
(pseudo code):
public class MyClass
{
//data protected by lock(this)
private object _data1;
private object _data2;
//data protected by lock(_list);
private object _data3;
private object _data4;
private List _list;
...
public void someMethod()
{
lock (this)
lock (_list)
{
//do something with data1 through data4
_list.someListMethod();
}
}
public void someOtherMethod()
{
_list.someListMethod();
}
}
Seems pretty innocent, right? Now suppose you didn't write the List class.
Someone else did or maybe it's part of Phobos or the .NET FCL or the Java
class libraries. And suppose it looks a bit like this:
public class List
{
private object _owner;
public List(object owner)
{
_owner = owner;
}
public void someListMethod()
{
lock (this)
lock (_owner)
{
//do something
}
}
}
See the problem? Take 2 threads: A and B. Thread A enters
MyClass.someMethod() and takes a lock on this (ie. the instance of MyClass).
Then it is preempted and thread B enters someOtherMethod(). It goes into
List.someListMethod() and takes a lock on this (ie. the instance of List).
It then attempts to lock on _owner (ie. the instance of MyClass). It can't
because thread A has that lock. Thread A can't continue because thread B has
the lock on the list instance. Bang - deadlock.
This example may seem a little contrived but this kind of thing has happened
and continues to happen in the real world. Why? Because any object instance
is lockable and *developers have little to no way of knowing what locks are
being taken by the code they're calling and in what order*. Because any
object can be locked, the following is true:
1. Developers will often just lock on this (or the TypeInfo when in static
scope) because it is "easier" and "cleaner". This ensures the problems
discussed above can occur. If developers had to explicitly create an object
to lock on, they will likely think harder about whether they expose that
object for others to lock. Most (all?) of the time they will realize that
there is no point doing that.
2. Malicious code can deliberately lock objects so that the host is
deadlocked if it also attempts to lock on those objects (for example,
consider a .NET assembly loaded into SQL Server 2005's CLR or a Java class
loaded into Eclipse)
3. As I already pointed out, every object carries around at least 4 extra
bytes on the heap - "just in case" it is ever locked. To me that is
enormously wasteful because most objects are never locked and I never lock
on public objects for the reasons above. I'd much rather be in direct
control of the memory being used to support locking.
Sorry to bang on about this. What can I say? I'm passionate. I daresay that
if you asked the designers of the .NET and Java threading support they will
express regret at allowing locks on arbitrary objects. Heck, I'd be happy to
do that for you if you like . . . ?
Regards,
Kent Boogaart
More information about the Digitalmars-d
mailing list