lockmanager.zip
Free
bin
LockManager.csproj.user
obj
Step1
App.ico
bin
obj
Step1.csproj.user
Step2
App.ico
bin
obj
Step2.csproj.user
Step3
App.ico
bin
obj
Step3.csproj.user
Step4
App.ico
bin
obj
Step4.csproj.user
Step5
App.ico
bin
obj
Step5.csproj.user
ThreeObjectsTest
App.ico
bin
obj
ThreeObjectsTest.csproj.user
|
/// <disclaimer>
/// This software is protected by your own conscience (c).
/// You can use it however you want and wherever you want.
/// You are allowed to change this code, copy this code, or delete this code.
/// You can buy this code; sell this code; present this code to your mom on her birthday.
/// You can replace author�s name with your own. You also can replace all the code with your own leaving
/// only author�s name.
/// The only thing you cannot do, is to violate this license agreement. You simply are not able to.
/// </disclaimer>
/// <author>
/// Sergei Zotin
/// szotin@shaw.ca
/// Burnaby, BC, Canada
/// Feel free to contact me for bug reports, feature requests and contract offers.
/// </author>
/// <version>1.6</version>
using System;
using System.Threading;
using ZEN.Threading;
using System.IO;
class A
{
private B b;
private int x;
private int y;
public B TheB
{
get
{
LockManager.Lock ( this );
try
{
return b;
}
finally
{
LockManager.Unlock ( this );
}
}
set
{
LockManager.Lock ( this );
try
{
b = value;
}
finally
{
LockManager.Unlock ( this );
}
}
}
public int X
{
get
{
LockManager.Lock ( this );
try
{
return x;
}
finally
{
LockManager.Unlock ( this );
}
}
// NEW: 1. Now we undo the change on DeadlockException. When DeadlockException is thrown we assigned
// NEW: value to x, but failed to assign it to b.X. The objects are in inconsistent state. Meanwhile
// NEW: all locks are released to before retrying the operation. That means, other threads
// NEW: may notice this inconsistence. To prevent it, we undo the assignment before releasing the lock.
// NEW: 2. External components may lock A themselves before calling A.X. If they do it, we are in
// NEW: trouble. We catch DeadlockException release all our locks and retry. But the external lock
// NEW: is still there. The deadlock is still there as well. To prevent it, we check
// NEW: LockManager.LockCount. If it is 1: we own all locks and can retry the operation. If not:
// NEW: we simply rethrow the exception allowing external components to release their locks and retry.
set
{
bool retry;
do
{
int oldX = x;
retry = false;
LockManager.Lock ( this );
try
{
Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
x = value;
b.X = value;
}
catch ( DeadlockException exc )
{
// undo the change
x = oldX;
// if this is the last lock - retry; else - rethrow - it should be retried on an upper level
if ( LockManager.LockCount == 1 )
retry = true;
else
throw exc;
}
finally
{
LockManager.Unlock ( this );
}
} while ( retry );
}
}
public int Y
{
get
{
LockManager.Lock ( this );
try
{
return y;
}
finally
{
LockManager.Unlock ( this );
}
}
set
{
LockManager.Lock ( this );
try
{
Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
y = value;
}
finally
{
LockManager.Unlock ( this );
}
}
}
}
class B
{
private A a;
private int x;
private int y;
public A TheA
{
get
{
LockManager.Lock ( this );
try
{
return a;
}
finally
{
LockManager.Unlock ( this );
}
}
set
{
LockManager.Lock ( this );
try
{
a = value;
}
finally
{
LockManager.Unlock ( this );
}
}
}
public int X
{
get
{
LockManager.Lock ( this );
try
{
return x;
}
finally
{
LockManager.Unlock ( this );
}
}
set
{
LockManager.Lock ( this );
try
{
Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
x = value;
}
finally
{
LockManager.Unlock ( this );
}
}
}
public int Y
{
get
{
LockManager.Lock ( this );
try
{
return y;
}
finally
{
LockManager.Unlock ( this );
}
}
// NEW: 1. Now we undo the change on DeadlockException. When DeadlockException is thrown we assigned
// NEW: value to y, but failed to assign it to a.Y. The objects are in inconsistent state. Meanwhile
// NEW: all locks are released to before retrying the operation. That means, other threads
// NEW: may notice this inconsistence. To prevent it, we undo the assignment before releasing the lock.
// NEW: 2. External components may lock B themselves before calling B.Y. If they do it, we are in
// NEW: trouble. We catch DeadlockException release all our locks and retry. But the external lock
// NEW: is still there. The deadlock is still there as well. To prevent it, we check
// NEW: LockManager.LockCount. If it is 1: we own all locks and can retry the operation. If not:
// NEW: we simply rethrow the exception allowing external components to release their locks and retry.
set
{
bool retry;
do
{
int oldY = y;
retry = false;
LockManager.Lock ( this );
try
{
Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
y = value;
a.Y = value;
}
catch ( DeadlockException exc )
{
// undo the change
y = oldY;
// if this is the last lock - retry; else - rethrow - it should be retried on an upper level
if ( LockManager.LockCount == 1 )
retry = true;
else
throw exc;
}
finally
{
LockManager.Unlock ( this );
}
} while ( retry );
}
}
}
class Step4
{
private A a;
private B b;
private Step4 ( A _a, B _b )
{
a = _a;
b = _b;
a.TheB = b;
b.TheA = a;
}
private void RunX ()
{
for ( int i = 0; i < 20; i++ )
{
a.X = i;
System.Console.WriteLine ( "Thread X: a.X={0}; b.X={1}", a.X, b.X );
}
}
private void RunY ()
{
for ( int i = 0; i < 20; i++ )
{
b.Y = i;
System.Console.WriteLine ( "Thread Y: a.Y={0}; b.Y={1}", a.Y, b.Y );
}
}
[STAThread]
static void Main ( string[] args )
{
A a = new A();
B b = new B();
Step4 step4 = new Step4 ( a, b );
TextWriter log = new StreamWriter ( "deadlock.log", false );
LockManager.Log = log;
Thread threadX = new Thread ( new ThreadStart ( step4.RunX ) );
Thread threadY = new Thread ( new ThreadStart ( step4.RunY ) );
threadX.Name = "X";
threadY.Name = "Y";
threadX.Start ();
threadY.Start ();
threadX.Join ();
threadY.Join ();
// closing the log
LockManager.Log = null;
log.Close ();
System.Console.WriteLine ( "Press Enter..." );
System.Console.In.Read();
System.Environment.Exit ( 0 );
}
}
|
By viewing downloads associated with this article you agree to the Terms of use and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.