1. 程式人生 > >C#執行緒間同步的幾種實現方式

C#執行緒間同步的幾種實現方式

一、使用訊號量

using System;
using System.Threading;

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

            Console.ReadKey();
        }
        //可同時有四個資源可訪問
        static SemaphoreSlim _semaphore = new SemaphoreSlim(4);

        static void AccessDatabase(string name, int seconds)
        {
            Console.WriteLine("{0} waits to access a database", name);
            _semaphore.Wait();
            Console.WriteLine("{0} was granted an access to a database", name);

            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine("{0} is completed", name);
            _semaphore.Release();
        }
    }
}

二、使用AutoResetEvent

using System;
using System.Threading;

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

            Console.WriteLine("waiting for another thread to complete work");
            _workerEvent.WaitOne();
            Console.WriteLine("first operation is completed!");
            Console.WriteLine("performing an operation on a main thread");
            Thread.Sleep(TimeSpan.FromSeconds(5));
            _mainEvent.Set();
            Console.WriteLine("now running the second operation on a second thread");
            _workerEvent.WaitOne();
            Console.WriteLine("second operation is completed!");

            Console.ReadKey();
        }

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

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

三、使用ManualResetEvent

using System;
using System.Threading;

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

            Console.ReadKey();
        }

        static ManualResetEventSlim _mainEvent = new ManualResetEventSlim(false);

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

四、使用CountDownEvent

using System;
using System.Threading;

namespace CountDownEventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.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();
            //等待所有訊號量返回
            //如果沒有Signal()返回,將永久性等待;或可使用帶時間引數方式等待
            _countdown.Wait();
            Console.WriteLine("both operation have been completed");
            _countdown.Dispose();

            Console.ReadKey();
        }
        //計數為2
        static CountdownEvent _countdown = new CountdownEvent(2);

        static void PerformOperation(string message, int seconds)
        {
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine(message);
            //返回訊號
            _countdown.Signal();
        }
    }
}