第2章 线程同步

  • 简介
  • 执行基本的原子操作
using System;
using System.Threading;
using static System.Console;

namespace Chapter2.Recipe1
{
	internal class Program
	{
		private static void Main(string[] args)
		{
			WriteLine("Incorrect counter");

			var c = new Counter();

			var t1 = new Thread(() => TestCounter(c));
			var t2 = new Thread(() => TestCounter(c));
			var t3 = new Thread(() => TestCounter(c));
			t1.Start();
			t2.Start();
			t3.Start();
			t1.Join();
			t2.Join();
			t3.Join();

			WriteLine($"Total count: {c.Count}");
			WriteLine("--------------------------");

			WriteLine("Correct counter");

			var c1 = new CounterNoLock();

			t1 = new Thread(() => TestCounter(c1));
			t2 = new Thread(() => TestCounter(c1));
			t3 = new Thread(() => TestCounter(c1));
			t1.Start();
			t2.Start();
			t3.Start();
			t1.Join();
			t2.Join();
			t3.Join();

			WriteLine($"Total count: {c1.Count}");
		}

		static void TestCounter(CounterBase c)
		{
			for (int i = 0; i < 100000; i++)
			{
				c.Increment();
				c.Decrement();
			}
		}

		class Counter : CounterBase
		{
			private int _count;

			public int Count => _count;

		    public override void Increment()
			{
				_count++;
			}

			public override void Decrement()
			{
				_count--;
			}
		}

		class CounterNoLock : CounterBase
		{
			private int _count;

			public int Count => _count;

		    public override void Increment()
			{
				Interlocked.Increment(ref _count);
			}

			public override void Decrement()
			{
				Interlocked.Decrement(ref _count);
			}
		}

		abstract class CounterBase
		{
			public abstract void Increment();

			public abstract void Decrement();
		}
	}
}

  • 使用Mutex类
using System;
using System.Threading;
using static System.Console;

namespace Chapter2.Recipe2
{
	class Program
	{
		static void Main(string[] args)
		{
			const string MutexName = "CSharpThreadingCookbook";

			using (var m = new Mutex(false, MutexName))
			{
				if (!m.WaitOne(TimeSpan.FromSeconds(5), false))
				{
					WriteLine("Second instance is running!");
				}
				else
				{
					WriteLine("Running!");
					ReadLine();
					m.ReleaseMutex();
				}
			}
		}
	}
}

  • 使用SemaphoreSlim类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe3
{
	class Program
	{
		static void Main(string[] args)
		{
			for (int i = 1; i <= 6; i++)
			{
				string threadName = "Thread " + i;
				int secondsToWait = 2 + 2 * i;
				var t = new Thread(() => AccessDatabase(threadName, secondsToWait));
				t.Start();
			}
		}

		static SemaphoreSlim _semaphore = new SemaphoreSlim(4);

		static void AccessDatabase(string name, int seconds)
		{
			WriteLine($"{name} waits to access a database");
			_semaphore.Wait();
			WriteLine($"{name} was granted an access to a database");
			Sleep(TimeSpan.FromSeconds(seconds));
			WriteLine($"{name} is completed");
			_semaphore.Release();
		}
	}
}

  • 使用AutoResetEvent类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe4
{
	class Program
	{
		static void Main(string[] args)
		{
			var t = new Thread(() => Process(10));
			t.Start();

			WriteLine("Waiting for another thread to complete work");
			_workerEvent.WaitOne();
			WriteLine("First operation is completed!");
			WriteLine("Performing an operation on a main thread");
			Sleep(TimeSpan.FromSeconds(5));
			_mainEvent.Set();
			WriteLine("Now running the second operation on a second thread");
			_workerEvent.WaitOne();
			WriteLine("Second operation is completed!");
		}

		private static AutoResetEvent _workerEvent = new AutoResetEvent(false);
		private static AutoResetEvent _mainEvent = new AutoResetEvent(false);

		static void Process(int seconds)
		{
			WriteLine("Starting a long running work...");
			Sleep(TimeSpan.FromSeconds(seconds));
			WriteLine("Work is done!");
			_workerEvent.Set();
			WriteLine("Waiting for a main thread to complete its work");
			_mainEvent.WaitOne();
			WriteLine("Starting second operation...");
			Sleep(TimeSpan.FromSeconds(seconds));
			WriteLine("Work is done!");
			_workerEvent.Set();
		}
	}
}

  • 使用ManualResetEventSlim类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe5
{
	class Program
	{
		static void Main(string[] args)
		{
			var t1 = new Thread(() => TravelThroughGates("Thread 1", 5));
			var t2 = new Thread(() => TravelThroughGates("Thread 2", 6));
			var t3 = new Thread(() => TravelThroughGates("Thread 3", 12));
			t1.Start();
			t2.Start();
			t3.Start();
			Sleep(TimeSpan.FromSeconds(6));
			WriteLine("The gates are now open!");
			_mainEvent.Set();
			Sleep(TimeSpan.FromSeconds(2));
			_mainEvent.Reset();
			WriteLine("The gates have been closed!");
			Sleep(TimeSpan.FromSeconds(10));
			WriteLine("The gates are now open for the second time!");
			_mainEvent.Set();
			Sleep(TimeSpan.FromSeconds(2));
			WriteLine("The gates have been closed!");
			_mainEvent.Reset();
		}

		static void TravelThroughGates(string threadName, int seconds)
		{
			WriteLine($"{threadName} falls to sleep");
			Sleep(TimeSpan.FromSeconds(seconds));
			WriteLine($"{threadName} waits for the gates to open!");
			_mainEvent.Wait();
			WriteLine($"{threadName} enters the gates!");
		}

		static ManualResetEventSlim _mainEvent = new ManualResetEventSlim(false);
	}
}

  • 使用CountDownEvent类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe6
{
	class Program
	{
		static void Main(string[] args)
		{
			WriteLine("Starting two operations");
			var t1 = new Thread(() => PerformOperation("Operation 1 is completed", 4));
			var t2 = new Thread(() => PerformOperation("Operation 2 is completed", 8));
			t1.Start();
			t2.Start();
			_countdown.Wait();
			WriteLine("Both operations have been completed.");
			_countdown.Dispose();
		}

		static CountdownEvent _countdown = new CountdownEvent(2);

		static void PerformOperation(string message, int seconds)
		{
			Sleep(TimeSpan.FromSeconds(seconds));
			WriteLine(message);
			_countdown.Signal();
		}
	}
}

  • 使用Barrier类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe7
{
	class Program
	{
		static void Main(string[] args)
		{
			var t1 = new Thread(() => PlayMusic("the guitarist", "play an amazing solo", 5));
			var t2 = new Thread(() => PlayMusic("the singer", "sing his song", 2));

			t1.Start();
			t2.Start();
		}

		static Barrier _barrier = new Barrier(2,
	b => WriteLine($"End of phase {b.CurrentPhaseNumber + 1}"));

		static void PlayMusic(string name, string message, int seconds)
		{
			for (int i = 1; i < 3; i++)
			{
				WriteLine("----------------------------------------------");
				Sleep(TimeSpan.FromSeconds(seconds));
				WriteLine($"{name} starts to {message}");
				Sleep(TimeSpan.FromSeconds(seconds));
				WriteLine($"{name} finishes to {message}");
				_barrier.SignalAndWait();
			}
		}
	}
}

  • 使用ReaderWriterLockSlim类
using System;
using System.Collections.Generic;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe8
{
	class Program
	{
		static void Main(string[] args)
		{
			new Thread(Read){ IsBackground = true }.Start();
			new Thread(Read){ IsBackground = true }.Start();
			new Thread(Read){ IsBackground = true }.Start();

			new Thread(() => Write("Thread 1")){ IsBackground = true }.Start();
			new Thread(() => Write("Thread 2")){ IsBackground = true }.Start();

			Sleep(TimeSpan.FromSeconds(30));
		}

		static ReaderWriterLockSlim _rw = new ReaderWriterLockSlim();
		static Dictionary<int, int> _items = new Dictionary<int, int>();

		static void Read()
		{
			WriteLine("Reading contents of a dictionary");
			while (true)
			{
				try
				{
					_rw.EnterReadLock();
					foreach (var key in _items.Keys)
					{
						Sleep(TimeSpan.FromSeconds(0.1));
					}
				}
				finally
				{
					_rw.ExitReadLock();
				}
			}
		}

		static void Write(string threadName)
		{
			while (true)
			{
				try
				{
					int newKey = new Random().Next(250);
					_rw.EnterUpgradeableReadLock();
					if (!_items.ContainsKey(newKey))
					{
						try
						{
							_rw.EnterWriteLock();
							_items[newKey] = 1;
							WriteLine($"New key {newKey} is added to a dictionary by a {threadName}");
						}
						finally
						{
							_rw.ExitWriteLock();
						}
					}
					Sleep(TimeSpan.FromSeconds(0.1));
				}
				finally
				{
					_rw.ExitUpgradeableReadLock();
				}
			}
		}
	}
}

  • 使用SpinWait类
using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;

namespace Chapter2.Recipe9
{
	class Program
	{
		static void Main(string[] args)
		{
			var t1 = new Thread(UserModeWait);
			var t2 = new Thread(HybridSpinWait);

			WriteLine("Running user mode waiting");
			t1.Start();
			Sleep(20);
			_isCompleted = true;
			Sleep(TimeSpan.FromSeconds(1));
			_isCompleted = false;
			WriteLine("Running hybrid SpinWait construct waiting");
			t2.Start();
			Sleep(5);
			_isCompleted = true;
		}

		static volatile bool _isCompleted = false;

		static void UserModeWait()
		{
			while (!_isCompleted)
			{
				Write(".");
			}
			WriteLine();
			WriteLine("Waiting is complete");
		}

		static void HybridSpinWait()
		{
			var w = new SpinWait();
			while (!_isCompleted)
			{
				w.SpinOnce();
				WriteLine(w.NextSpinWillYield);
			}
			WriteLine("Waiting is complete");
		}
	}
}

posted on 2019-05-14 17:06  威武的祥哥  阅读(114)  评论(0)    收藏  举报

导航