|
/// <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 ThreeObjectsTest
{
// If you set NUMBER_OF_THREADS to a big value and NUMBER_OF_SYNC_OBJECTS to a small value
// (for example NUMBER_OF_THREADS = 20; NUMBER_OF_SYNC_OBJECTS = 2; - may be you need other values
// - different computers behave differently), you'll probably face a deadlock of a very interesting
// type. LockManager will continuously interrupt wrong thread, which will always be replaced by the
// similar one, repeating deadlock again and again without any progress.
// This bug was fixed in version 2.0. However, I don't distribute version 2 freely. I have spent a lot
// of time debuging and fixing various type of deadlocks, and I feel, I need some compensation for my work.
// Contact me at szotin@shaw.ca if you need better version of LockManager.
private const int NUMBER_OF_THREADS = 3;
private const int NUMBER_OF_SYNC_OBJECTS = 3;
private const int LOOP_ITTERATIONS = 20;
// 0 - no log; 1 - console; 2 - file "deadlock.log"
private const int LOG_TO = 1;
private class ThreadClass
{
private static object m_go = new Object();
private object m_sync1;
private object m_sync2;
private Thread m_thread;
public ThreadClass ( string name, object sync1, object sync2 )
{
m_sync1 = sync1;
m_sync2 = sync2;
m_thread = new Thread ( new ThreadStart ( Run ) );
m_thread.Name = name;
m_thread.Start();
}
public static void Go ()
{
lock ( m_go )
{
Monitor.PulseAll ( m_go );
}
}
public void Join ()
{
m_thread.Join ();
}
private void Run ()
{
lock ( m_go )
{
Monitor.Wait ( m_go );
}
for ( int i = 0; i < LOOP_ITTERATIONS; i++ )
{
bool retry = true;
bool printed = false;
while ( retry )
{
retry = false;
LockManager.Lock ( m_sync1 );
if ( !printed )
{
System.Console.WriteLine ( "{0}: a.{1}", Thread.CurrentThread.Name, i + 1 );
printed = true;
}
try
{
LockManager.Lock ( m_sync2 );
try
{
System.Console.WriteLine ( "{0}: b.{1}", Thread.CurrentThread.Name, i + 1 );
}
finally
{
LockManager.Unlock ( m_sync2 );
}
}
catch ( DeadlockException )
{
//System.Console.WriteLine ( "{0}: lock failed, retrying", Thread.CurrentThread.Name );
Thread.Sleep ( 100 );
retry = true;
}
finally
{
LockManager.Unlock ( m_sync1 );
}
}
}
}
}
public static void Main ( string[] args )
{
int logType = LOG_TO;
switch ( logType )
{
case 1:
LockManager.Log = System.Console.Out;
break;
case 2:
LockManager.Log = new StreamWriter ( "deadlock.log", false );
break;
}
System.Console.WriteLine ( "Initializing threads..." );
string[] sync = new String[NUMBER_OF_SYNC_OBJECTS];
for ( int i = 0; i < NUMBER_OF_SYNC_OBJECTS; i++ )
sync[i] = "sync " + ( i + 1 );
ThreadClass[] threads = new ThreadClass[NUMBER_OF_THREADS];
int currentSyncObject = 0;
for ( int i = 0; i < NUMBER_OF_THREADS; i++ )
{
int nextSyncObject = currentSyncObject + 1;
if ( nextSyncObject >= NUMBER_OF_SYNC_OBJECTS )
nextSyncObject = 0;
object sync1 = sync[currentSyncObject];
object sync2 = sync[nextSyncObject];
currentSyncObject = nextSyncObject;
threads[i] = new ThreadClass ( "Thread " + ( i + 1 ), sync1, sync2 );
}
System.Console.Write ( "Waiting 3 seconds while all the threads start" );
for ( int i = 0; i < 3; i++ )
{
Thread.Sleep ( 1000 );
System.Console.Write ( "." );
}
System.Console.WriteLine();
System.Console.WriteLine ( "Starting..." );
int start = Environment.TickCount;
ThreadClass.Go();
for ( int i = 0; i < NUMBER_OF_THREADS; i++ )
threads[i].Join ();
System.Console.WriteLine ( "{0} ms.", Environment.TickCount - start );
// close the file if opened
if ( logType == 2 )
{
TextWriter writer = LockManager.Log;
LockManager.Log = null;
writer.Flush ();
writer.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 Service 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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.