第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");
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/lxwuse2008/p/10858550.html