⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 step5.cs

📁 这五个程序都经实验
💻 CS
字号:
/// <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 authors name with your own. You also can replace all the code with your own leaving
/// only authors 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;
	
	// NEW: By using private lock object instead of this, we guarantee that users of A will not
	// NEW: take part in our synchization game.
	// NEW: That allow us to make some assumptions about a state of locks.
	private string lockObject = "LockA";

	public B TheB
	{
		// NEW: It is never involved in cascade locks (we can be sure, because lock object is now private),
		// NEW: so deadlock cannot be a problem here.
		// NEW: We can use lock(lockObject) instead of LockManager.Lock(lockObject), which works much faster.
		get
		{
			lock ( lockObject )
			{
				return b;
			}
		}
		
		// NEW: It is never involved in cascade locks (we can be sure, because lock object is now private),
		// NEW: so deadlock cannot be a problem here.
		// NEW: We can use lock(lockObject) instead of LockManager.Lock(lockObject), which works much faster.
		set
		{
			lock ( lockObject )
			{
				b = value;
			}
		}
	}

	public int X
	{
		get
		{
			LockManager.Lock ( lockObject );
			try
			{
				return x;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
		
		// NEW: 1. We can change the order of assignments to avoud undoing. The idea is: just not to set x before b.X
		// NEW:    is set.
		// NEW: 2. Now we use private lock object, so we can be sure that external components do not lock either A or B.
		// NEW:    At the same time we never use X internally, so when it is called, either A or B are never locked. This
		// NEW:    means that even if LockManager.LockCount is not 1, we can fix the deadlock right here. External locks
		// NEW:    don't take part in it. LockManager.LockCount is a time consuming operation (it makes some loops throw
		// NEW:    internal LockManager arrays, which themselves are synchronized). Avoiding it definitely improves
		// NEW:    performance.
		set
		{
			bool retry;
			do
			{
				retry = false;
				LockManager.Lock ( lockObject );
				try
				{
					Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
					b.X = value;
					x = value;
				}
				catch ( DeadlockException )
				{
					retry = true;
				}
				finally
				{
					LockManager.Unlock ( lockObject );
				}
			} while ( retry );
		}
	}

	public int Y
	{
		get
		{
			LockManager.Lock ( lockObject );
			try
			{
				return y;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
		
		set
		{
			LockManager.Lock ( lockObject );
			try
			{
				Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
				y = value;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
	}
}

class B
{
	private A a;
	private int x;
	private int y;

	// NEW: By using private lock object instead of this, we guarantee that users of A will not
	// NEW: take part in our synchization game.
	// NEW: That allow us to make some assumptions about a state of locks.
	private string lockObject = "LockB";

	public A TheA
	{
		// NEW: It is never involved in cascade locks (we can be sure, because lock object is now private),
		// NEW: so deadlock cannot be a problem here.
		// NEW: We can use lock(lockObject) instead of LockManager.Lock(lockObject), which works much faster.
		get
		{
			lock ( lockObject )
			{
				return a;
			}
		}
		
		// NEW: It is never involved in cascade locks (we can be sure, because lock object is now private),
		// NEW: so deadlock cannot be a problem here.
		// NEW: We can use lock(lockObject) instead of LockManager.Lock(lockObject), which works much faster.
		set
		{
			lock ( lockObject )
			{
				a = value;
			}
		}
	}

	public int X
	{
		get
		{
			LockManager.Lock ( lockObject );
			try
			{
				return x;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
		set
		{
			LockManager.Lock ( lockObject );
			try
			{
				Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
				x = value;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
	}

	public int Y
	{
		get
		{
			LockManager.Lock ( lockObject );
			try
			{
				return y;
			}
			finally
			{
				LockManager.Unlock ( lockObject );
			}
		}
		
		// NEW: 1. We can change the order of assignments to avoud undoing. The idea is: just not to set y before a.Y
		// NEW:    is set.
		// NEW: 2. Now we use private lock object, so we can be sure that external components do not lock either A or B.
		// NEW:    At the same time we never use X internally, so when it is called, either A or B are never locked. This
		// NEW:    means that even if LockManager.LockCount is not 1, we can fix the deadlock right here. External locks
		// NEW:    don't take part in it. LockManager.LockCount is a time consuming operation (it makes some loops throw
		// NEW:    internal LockManager arrays, which themselves are synchronized). Avoiding it definitely improves
		// NEW:    performance.
		set
		{
			bool retry;
			do
			{
				retry = false;
				LockManager.Lock ( lockObject );
				try
				{
					Thread.Sleep ( 10 ); // just to increase the odds of a deadlock
					a.Y = value;
					y = value;
				}
				catch ( DeadlockException )
				{
					retry = true;
				}
				finally
				{
					LockManager.Unlock ( lockObject );
				}
			} 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 );
		}
	}

	// NEW: We know the deadlocks are there. We can save some time by not logging them.
	// NEW: So we don't turn the log on.
	[STAThread]
	static void Main ( string[] args )
	{
		A a = new A();
		B b = new B();
		Step4 step4 = new Step4 ( a, b );

		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 ();

		System.Console.WriteLine ( "Press Enter..." );
		System.Console.In.Read();
		System.Environment.Exit ( 0 );
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -