lock
statements and
method calls. It builds call graph uses it to construct resource graph.
If there is a loop in resource graph then deadlock may happen if method contains
this lock statements are executed concurrently.
Lets look at the simple example:
class DeadlockProneClass { object monitor1 = new object(); object monitor2 = new object(); public void method1() { lock (monitor1) { lock (monitor2) { // do something } } } public void method2() { lock (monitor2) { lock (monitor1) { // do something } } } }If methods
method1
and method2
are executed concurrently,
it can happen that thread executing method1
locks monitor1
and wait for
monitor2
. At the same time thread executing method2
locks
monitor2
and waits for monitor1
. In this case
these two threads blocks each other - none of them can continue execution.
Such situation is called deadlock.
And this is what CSLint tries to detect in your code.
The example above seems to be artificial and not frequently happen in real life:
why programmer has to lock two objects and do it in different order?
But it is just the trivial example of deadlock. Some method m1
may lock some resource r1
and then invoke some other method m2
of the other class. m2
can invoke m3
and so on...
Some of the methods in this invocation chain can lock another resource r2
.
So we will have edge r1->r2
in resource graph.
There can exist some other invocation chain (of completely different methods)
which cause that resource r2
is locked before r1
.
And one again we have conditions for possible deadlock appearance.
Below is the most trivial example of such situation:
class Class1 { public void method(Class2 c2) { lock (this) { c2.method(this); } } } class Class2 { public void method(Class1 c1) { lock (this) { c1.method(this); } } }
Reflector
CSLint/CSLintAddin/bin/Debug/CSLintAddin.dll
)Tools
menu choose "Detect Deadlocks"
itemCSLint\CSLintAddin\bin\Debug
directory - it already contains CSLint add-in loaded as well as test assembly, where
you can check how detection of deadlocks works.
CSLint will show message with list of all detected loops (each loop corresponds
to the possible deadlock). Information about loop contains locked resources
and invocation chains which connects code locking these resources.
Also for your conviniece information about detected deadlocks is saved in
deadlock.lst
file which is create in the directpry from which
you have started Reflect. Information about deadlocks loks something like this:
Loop 1: lock(Tests.Test4.a) in method Tests.Test4.f1 can cause deadlock Loop 1: lock(Tests.Test4.b) in method Tests.Test4.f2 can cause deadlock Loop 2: lock(Tests.Test3.B) in method Tests.Test3.B.foo can cause deadlock Loop 2: called from Tests.Test3.g Loop 2: called from Tests.Test3.A.foo Loop 2: lock(Tests.Test3.A) in method Tests.Test3.A.foo can cause deadlock Loop 2: called from Tests.Test3.f Loop 2: called from Tests.Test3.B.foo Loop 3: lock(Tests.Test2.a) in method Tests.Test2.f1 can cause deadlock Loop 3: lock(Tests.Test2.b) in method Tests.Test2.f2 can cause deadlock Loop 4: lock(Tests.Test1.Class5.monitor) in method Tests.Test1.Class5.method1 can cause deadlock Loop 4: called from Tests.Test1.Class4.method Loop 4: lock(Tests.Test1.Class4.monitor) in method Tests.Test1.Class5.method2 can cause deadlock Loop 5: lock(Tests.Test1.Class3.monitor2) in method Tests.Test1.Class3.method1 can cause deadlock Loop 5: lock(Tests.Test1.Class3.monitor1) in method Tests.Test1.Class3.method2 can cause deadlock Loop 6: lock(Tests.Test1.Class2) in method Tests.Test1.Class2.method can cause deadlock Loop 6: called from Tests.Test1.Class1.method Loop 6: lock(Tests.Test1.Class1) in method Tests.Test1.Class1.method can cause deadlock Loop 6: called from Tests.Test1.Class2.methodIf your application is large, CSLint analysis can take significant amount of time, please be patient.
x
of class Y
, then CSLint assumes then everywhere in your application
Y.x
refers to the same object instance (so it is the single resource).
Certainly it may be not true, in this case deadlock detected by CSLint will be a false alarm.
Also CSLint assumes that if method m1
MAY call m2
, then
it always calls it. Moreover, it is clear that in code fragment:
if (someCondition) { method1(); } else { method2(); }only one of
method1
and method2
can be actually invoked.
But CSLint assumes that both methods are invoked.lock
constructions.
It doesn't consider Monitor.Enter
, ReaderWriterLock.AcquireReradeLock
methods as well as any other .Net synchronization primitives.I will provide e-mail support and help you with development of CSLint add-in for .Net Reflector.
Look for new version at my homepage | E-Mail me about bugs and problems