限定使用,同步机制

主题材料抽象:当某一能源相像时刻同意肯定数额的线程使用的时候,需求有个机制来阻塞多余的线程,直到能源重新变得可用。
线程同步方案:Semaphore、SemaphoreSlim、CountdownEvent
方案天性:限量供应;除全数者外,其余人无条件等待;先到先得,不曾前后相继顺序

当多个职分或线程并行运营时,难以幸免的对少数有限的财富进行并发的拜谒。能够考虑选择功率信号量来展开那地方的垄断(System.Threading.Semaphore)是意味着叁个Windows内核的复信号量对象。要是预测等待的日子超短,能够虚构动用塞马phoreSlim,它则带来的开销更加小。.NetFrameWork中的功率信号量通过追踪步向和离开的职责或线程来和谐对财富的探访。时域信号量需求精晓财富的最大数目,当二个职分步入时,财富计数器会被减1,当计数器为0时,假使有任务访问财富,它会被卡住,直到有职分离开停止。
万后生可畏须要有跨进度或AppDomain的合作一时间,能够思考接收Semaphore。Semaphore是得到的Windows 内核的确定性信号量,所以在一切连串中是卓有成效的。它至关心注重要的接口是Release和WaitOne,使用的方法和SemaphoreSlim是意气风发律的。
信号量Semaphore是别的一个CL福睿斯中的内核同步对象。在.net中,类Semaphore封装了这一个目标。与标准的排他锁对象(Monitor,Mutex,SpinLock)区别的是,它不是叁个排他的锁对象,它与SemaphoreSlim,ReaderWriteLock等相通允许八个轻易的线程同有的时候候访问分享内部存款和储蓄器能源。

   

1.简介

1、Semaphore类
      用于调控线程的会见数量,暗中同意的构造函数为initialCount和maximumCount,表示暗中认可设置的时限信号量个数和最大非数字信号量个数。当您WaitOne的时候,复信号量自减,当Release的时候,能量信号量自增,不过当时限信号量为0的时候,后续的线程就不能够获得WaitOne了,所以必得等待先前的线程通过Release来刑释。

Semaphore就就好像八个栅栏,有肯定的体量,当此中的线程数量到达安装的最大值时候,就从未线程能够步向。然后,若是二个线程职业造成以往出来了,这下贰个线程就足以进去了。Semaphore的WaitOne或Release等操作分别将机关地依次减少恐怕依次增加复信号量的眼下计数值。当线程试图对计数值已经为0的频限信号量奉行WaitOne操作时,线程将卡住直到计数值大于0。在构造Semaphore时,起码要求2个参数。实信号量的上马体量和最大的体量。

     承接上生龙活虎篇,我们承接说下.net4.0中的同步机制,是的,当出现了并行计算的时候,轻量等级的黄金年代道机制应际而生,在信号量这一块

新的轻量级同步原语:Barrier,CountdownEvent,马努alResetEventSlim,SemaphoreSlim,SpinLock,SpinWait。轻量级同步原语只可以用在二个经过内。而相应的那多少个重量级版本扶植跨进度的联合签名。

图片 1图片 2

Semaphore的WaitOne恐怕Release方法的调用大概会损耗1阿秒的系统时间,而优化后的SemaphoreSlim则需求大致五分之一阿秒。在图谋中山大学量一再利用它的时候SemaphoreSlim依然优势分明,加上SemaphoreSlim还丰盛了许多接口,越发实惠大家进行支配,所以在4.0后头的多线程开拓中,推荐应用SemaphoreSlim。SemaphoreSlim的贯彻如下:

并发了黄金年代种类的轻量级,今天摧枯拉朽介绍下边包车型地铁3个模拟信号量 Countdown伊芙nt,SemaphoreSlim,ManualResetEventSlim。

2.Barrier 

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(Run1);
            t1.Start();
            Thread t2 = new Thread(Run2);
            t2.Start();
            Thread t3 = new Thread(Run3);
            t3.Start();
            Console.ReadKey();
        }

        //初始可以授予2个线程信号,因为第3个要等待前面的Release才能得到信号
        static Semaphore sem = new Semaphore(2, 10);

        static void Run1()
        {
            sem.WaitOne();
            Console.WriteLine("大家好,我是Run1;"   DateTime.Now.ToString("mm:ss"));

            //两秒后
            Thread.Sleep(2000);
            sem.Release();
        }

        static void Run2()
        {
            sem.WaitOne();
            Console.WriteLine("大家好,我是Run2;"   DateTime.Now.ToString("mm:ss"));

            //两秒后
            Thread.Sleep(2000);
            sem.Release();
        }

        static void Run3()
        {
            sem.WaitOne();
            Console.WriteLine("大家好,我是Run3;"   DateTime.Now.ToString("mm:ss"));

            //两秒后
            Thread.Sleep(2000);
            sem.Release();
        }
    }
}
public class SemaphoreSlim : IDisposable
    {  
        private volatile int m_currentCount; //可用数的资源数,<=0开始阻塞
        private readonly int m_maxCount;
        private volatile int m_waitCount; //阻塞的线程数
        private object m_lockObj;
        private volatile ManualResetEvent m_waitHandle;
        private const int NO_MAXIMUM = Int32.MaxValue;
        //Head of list representing asynchronous waits on the semaphore.
        private TaskNode m_asyncHead;
        // Tail of list representing asynchronous waits on the semaphore.
        private TaskNode m_asyncTail;
         // A pre-completed task with Result==true
        private readonly static Task<bool> s_trueTask =
            new Task<bool>(false, true, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));

        public SemaphoreSlim(int initialCount) : this(initialCount, NO_MAXIMUM){ }        
        public SemaphoreSlim(int initialCount, int maxCount)
        {
            if (initialCount < 0 || initialCount > maxCount)
            {
                throw new ArgumentOutOfRangeException("initialCount", initialCount, GetResourceString("SemaphoreSlim_ctor_InitialCountWrong"));
            }
            if (maxCount <= 0)
            {
                throw new ArgumentOutOfRangeException("maxCount", maxCount, GetResourceString("SemaphoreSlim_ctor_MaxCountWrong"));
            }
            m_maxCount = maxCount;
            m_lockObj = new object();
            m_currentCount = initialCount;
        }
        public void Wait(){Wait(Timeout.Infinite, new CancellationToken());}
        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckDispose();
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
            }
            cancellationToken.ThrowIfCancellationRequested();
            uint startTime = 0;
            if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout > 0)
            {
                startTime = TimeoutHelper.GetTime();
            }

            bool waitSuccessful = false;
            Task<bool> asyncWaitTask = null;
            bool lockTaken = false;

            CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler, this);
            try
            {
                SpinWait spin = new SpinWait();
                while (m_currentCount == 0 && !spin.NextSpinWillYield)
                {
                    spin.SpinOnce();
                }
                try { }
                finally
                {
                    Monitor.Enter(m_lockObj, ref lockTaken);
                    if (lockTaken)
                    {
                        m_waitCount  ;
                    }
                }

                // If there are any async waiters, for fairness we'll get in line behind
                if (m_asyncHead != null)
                {
                    Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't");
                    asyncWaitTask = WaitAsync(millisecondsTimeout, cancellationToken);
                }
                // There are no async waiters, so we can proceed with normal synchronous waiting.
                else
                {
                    // If the count > 0 we are good to move on.
                    // If not, then wait if we were given allowed some wait duration
                    OperationCanceledException oce = null;
                    if (m_currentCount == 0)
                    {
                        if (millisecondsTimeout == 0)
                        {
                            return false;
                        }
                        // Prepare for the main wait...
                        // wait until the count become greater than zero or the timeout is expired
                        try
                        {
                            waitSuccessful = WaitUntilCountOrTimeout(millisecondsTimeout, startTime, cancellationToken);
                        }
                        catch (OperationCanceledException e) { oce = e; }
                    }

                    Contract.Assert(!waitSuccessful || m_currentCount > 0, "If the wait was successful, there should be count available.");
                    if (m_currentCount > 0)
                    {
                        waitSuccessful = true;
                        m_currentCount--;
                    }
                    else if (oce != null)
                    {
                        throw oce;
                    }
                    if (m_waitHandle != null && m_currentCount == 0)
                    {
                        m_waitHandle.Reset();
                    }
                }
            }
            finally
            {
                // Release the lock
                if (lockTaken)
                {
                    m_waitCount--;
                    Monitor.Exit(m_lockObj);
                }

                // Unregister the cancellation callback.
                cancellationTokenRegistration.Dispose();
            }
            return (asyncWaitTask != null) ? asyncWaitTask.GetAwaiter().GetResult() : waitSuccessful;
        }

        private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, CancellationToken cancellationToken)
        {
            int remainingWaitMilliseconds = Timeout.Infinite;
            //Wait on the monitor as long as the count is zero
            while (m_currentCount == 0)
            {
                // If cancelled, we throw. Trying to wait could lead to deadlock.
                cancellationToken.ThrowIfCancellationRequested();
                if (millisecondsTimeout != Timeout.Infinite)
                {
                    remainingWaitMilliseconds = TimeoutHelper.UpdateTimeOut(startTime, millisecondsTimeout);
                    if (remainingWaitMilliseconds <= 0)
                    {
                        // The thread has expires its timeout
                        return false;
                    }
                }
                // ** the actual wait **
                if (!Monitor.Wait(m_lockObj, remainingWaitMilliseconds))
                {
                    return false;
                }
            }
            return true;
        }
        public Task<bool> WaitAsync(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            CheckDispose();
            // Validate input
            if (millisecondsTimeout < -1)
            {
                throw new ArgumentOutOfRangeException("totalMilliSeconds", millisecondsTimeout, GetResourceString("SemaphoreSlim_Wait_TimeoutWrong"));
            }
            // Bail early for cancellation
            if (cancellationToken.IsCancellationRequested)
                return Task.FromCancellation<bool>(cancellationToken);

            lock (m_lockObj)
            {
                // If there are counts available, allow this waiter to succeed.
                if (m_currentCount > 0)
                {
                    --m_currentCount;
                    if (m_waitHandle != null && m_currentCount == 0) m_waitHandle.Reset();
                    return s_trueTask;
                }
                    // If there aren't, create and return a task to the caller.
                    // The task will be completed either when they've successfully acquired
                    // the semaphore or when the timeout expired or cancellation was requested.
                else
                {
                    Contract.Assert(m_currentCount == 0, "m_currentCount should never be negative");
                    var asyncWaiter = CreateAndAddAsyncWaiter();
                    return (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled) ?
                        asyncWaiter :
                        WaitUntilCountOrTimeoutAsync(asyncWaiter, millisecondsTimeout, cancellationToken);
                }
            }
        }

        /// <summary>Creates a new task and stores it into the async waiters list.</summary>
        /// <returns>The created task.</returns>
        private TaskNode CreateAndAddAsyncWaiter()
        {
            Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held");
            // Create the task
            var task = new TaskNode();
            // Add it to the linked list
            if (m_asyncHead == null)
            {
                Contract.Assert(m_asyncTail == null, "If head is null, so too should be tail");
                m_asyncHead = task;
                m_asyncTail = task;
            }
            else
            {
                Contract.Assert(m_asyncTail != null, "If head is not null, neither should be tail");
                m_asyncTail.Next = task;
                task.Prev = m_asyncTail;
                m_asyncTail = task;
            }
            // Hand it back
            return task;
        }

        private async Task<bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
        {
            Contract.Assert(asyncWaiter != null, "Waiter should have been constructed");
            Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held");
            using (var cts = cancellationToken.CanBeCanceled ?
                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default(CancellationToken)) :
                new CancellationTokenSource())
            {
                var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token));
                if (asyncWaiter == await waitCompleted.ConfigureAwait(false))
                {
                    cts.Cancel(); // ensure that the Task.Delay task is cleaned up
                    return true; // successfully acquired
                }
            }

            // If we get here, the wait has timed out or been canceled.

            // If the await completed synchronously, we still hold the lock.  If it didn't,
            // we no longer hold the lock.  As such, acquire it.
            lock (m_lockObj)
            {
                // Remove the task from the list.  If we're successful in doing so,
                // we know that no one else has tried to complete this waiter yet,
                // so we can safely cancel or timeout.
                if (RemoveAsyncWaiter(asyncWaiter))
                {
                    cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred
                    return false; // timeout occurred
                }
            }

            // The waiter had already been removed, which means it's already completed or is about to
            // complete, so let it, and don't return until it does.
            return await asyncWaiter.ConfigureAwait(false) await asyncWaiter.ConfigureAwait(false);
        }
        public int Release(){ return Release(1);}

        public int Release(int releaseCount)
        {
            CheckDispose();

            // Validate input
            if (releaseCount < 1)
            {
                throw new ArgumentOutOfRangeException( "releaseCount", releaseCount, GetResourceString("SemaphoreSlim_Release_CountWrong"));
            }
            int returnCount;

            lock (m_lockObj)
            {
                // Read the m_currentCount into a local variable to avoid unnecessary volatile accesses inside the lock.
                int currentCount = m_currentCount;
                returnCount = currentCount;

                // If the release count would result exceeding the maximum count, throw SemaphoreFullException.
                if (m_maxCount - currentCount < releaseCount)
                {
                    throw new SemaphoreFullException();
                }

                // Increment the count by the actual release count
                currentCount  = releaseCount;

                // Signal to any synchronous waiters
                int waitCount = m_waitCount;
                if (currentCount == 1 || waitCount == 1)
                {
                    Monitor.Pulse(m_lockObj);
                }
                else if (waitCount > 1)
                {
                    Monitor.PulseAll(m_lockObj);
                }

                // Now signal to any asynchronous waiters, if there are any.  While we've already
                // signaled the synchronous waiters, we still hold the lock, and thus
                // they won't have had an opportunity to acquire this yet.  So, when releasing
                // asynchronous waiters, we assume that all synchronous waiters will eventually
                // acquire the semaphore.  That could be a faulty assumption if those synchronous
                // waits are canceled, but the wait code path will handle that.
                if (m_asyncHead != null)
                {
                    Contract.Assert(m_asyncTail != null, "tail should not be null if head isn't null");
                    int maxAsyncToRelease = currentCount - waitCount;
                    while (maxAsyncToRelease > 0 && m_asyncHead != null)
                    {
                        --currentCount;
                        --maxAsyncToRelease;

                        // Get the next async waiter to release and queue it to be completed
                        var waiterTask = m_asyncHead;
                        RemoveAsyncWaiter(waiterTask); // ensures waiterTask.Next/Prev are null
                        QueueWaiterTask(waiterTask);
                    }
                }
                m_currentCount = currentCount;

                // Exposing wait handle if it is not null
                if (m_waitHandle != null && returnCount == 0 && currentCount > 0)
                {
                    m_waitHandle.Set();
                }
            }

            // And return the count
            return returnCount;
        }

        ///Removes the waiter task from the linked list.</summary>
        private bool RemoveAsyncWaiter(TaskNode task)
        {
            Contract.Requires(task != null, "Expected non-null task");
            Contract.Assert(Monitor.IsEntered(m_lockObj), "Requires the lock be held");

            // Is the task in the list?  To be in the list, either it's the head or it has a predecessor that's in the list.
            bool wasInList = m_asyncHead == task || task.Prev != null;

            // Remove it from the linked list
            if (task.Next != null) task.Next.Prev = task.Prev;
            if (task.Prev != null) task.Prev.Next = task.Next;
            if (m_asyncHead == task) m_asyncHead = task.Next;
            if (m_asyncTail == task) m_asyncTail = task.Prev;
            Contract.Assert((m_asyncHead == null) == (m_asyncTail == null), "Head is null iff tail is null");

            // Make sure not to leak
            task.Next = task.Prev = null;

            // Return whether the task was in the list
            return wasInList;
        }
        private static void QueueWaiterTask(TaskNode waiterTask)
        {
            ThreadPool.UnsafeQueueCustomWorkItem(waiterTask, forceGlobal: false);
        }
        public int CurrentCount
        {
            get { return m_currentCount; }
        }
        public WaitHandle AvailableWaitHandle
        {
            get
            {
                CheckDispose();
                if (m_waitHandle != null)
                    return m_waitHandle;
                lock (m_lockObj)
                {
                    if (m_waitHandle == null)
                    {
                        m_waitHandle = new ManualResetEvent(m_currentCount != 0);
                    }
                }
                return m_waitHandle;
            }
        }
        private sealed class TaskNode : Task<bool>, IThreadPoolWorkItem
        {
            internal TaskNode Prev, Next;
            internal TaskNode() : base() {}

            [SecurityCritical]
            void IThreadPoolWorkItem.ExecuteWorkItem()
            {
                bool setSuccessfully = TrySetResult(true);
                Contract.Assert(setSuccessfully, "Should have been able to complete task");
            }

            [SecurityCritical]
            void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { /* nop */ }
        }
    }

 

首要成员

Program

SemaphoreSlim类有多少个私有字段很主要,m_currentCount表示可用财富,借使m_currentCount>0老是调用Wait都会减1,当m_currentCount<=0时重新调用Wait方法就能够阻塞。每回调用Release方法m_currentCount都会加1.m_maxCount表示最大可用财富数,是在构造函数中钦点的。m_waitCount代表如今不通的线程数。TaskNode m_asyncHead,m_asyncTail那2个变量重要用于异步方法。

一:CountdownEvent

1)public Barrier(int participantCount, Action<Barrier> postPhaseAction);构造 函数,participantCount:参加的线程个数(参预者的个数), postPhaseAction每一个阶段后进行的操作。

在上述的主意中Release()方法相当于自增贰个信号量,Release(5)自增5个时限信号量。只是,Release()到构造函数的第二个参数maximumCount的值就不能再自增了。

小编们第一来探视Wait方法,这里还会有它的异步版本WaitAsync。在Wait方法中第意气风发检查m_currentCount是或不是为0,假若是大家用SpinWait自旋十回;跋扈二遍Wait都必要锁住m_lockObj对象,m_asyncHead != null表示近些日子曾经存在异步的靶子,所以大家调用WaitAsync方法,若无那么大家调用WaitUntilCountOrTimeout方法,该形式在m_currentCount==0会阻塞到到m_currentCount不为0只怕逾期;看见WaitUntilCountOrTimeout方法中【if (!Monitor.Wait(m_lockObj, remainingWaitMilliseconds))】,就很明了Wait方法中【CancellationTokenRegistration cancellationTokenRegistration = cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceledEventHandler, this)】存在的缘由了,确实很抢眼【这里和马努alReset伊芙ntSlim相仿】。以后大家回去WaitAsync方法,该措施也是率先检查m_currentCount是不是大于0,大于直接重返。否者调用CreateAndAddAsyncWaiter创制一个Task<bool>【Task<bool>是四个链表结构】,若无废除且超时超越-1,那么就调用WaitUntilCountOrTimeoutAsync方法,该方式首先包装三个Task【var waitCompleted = Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token))】然后等待线程【await waitCompleted.ConfigureAwait(false)】重回的是asyncWaiter只怕另三个Delay的Task。若是回去的不是asyncWaiter表明已经晚点须求调用RemoveAsyncWaiter,然后重临await asyncWaiter.ConfigureAwait(false),纵然回去的是asyncWaiter,那么就调用Cancel方法。那么这里的asyncWaiter.ConfigureAwait(false)何时退出了【也许说不阻塞】,那将要看Release中的QueueWaiterTask方法了。

     这种利用时限信号状态的同台基元特别切合在动态的fork,join的景况,它接受“时域信号计数”的主意,就比如那样,多个麻将桌只好包容4个

2) public void SignalAndWait();发出时限信号,表示参加者已高达屏障并等待全体别的参加者也达成屏障。

Semaphore可用于进度级交互。

QueueWaiterTask方法或调用TaskNode的ExecuteWorkItem方法。
那今后我们来探视Release方法,该格局会把currentCount加1,然后把等待线程转为就绪线程【Monitor.Pulse(m_lockObj)或 Monitor.PulseAll(m_lockObj)】,假设存在异步的话,看看还足以自由几个异步task【 int maxAsyncToRelease = currentCount - waitCount】,这里Release的注释相当的重大,只是没怎么通晓,现释同步的waiters,然后在出狱异步的waiters,可是自由同步后锁的能源未有自由,在刑释异步的waiters时候是把currentCount减1,那样认为异步waiters优先获得财富。也不明了自家的掌握是否科学?
1)当ConfigureAwait(true),代码由协助实行试行步向异步实行时,当前协作执行的线程上下文音信(比方HttpConext.Current,Thread.CurrentThread.CurrentCulture)就能够被擒获并保留至SynchronizationContext中,供异步奉行中动用,况且供异步实施到位之后(await之后的代码)的联手实行中使用(固然await之后是叁只推行的,然而发生了线程切换,会在其它一个线程中试行「ASP.NET场景」)。这几个捕获当然是有代价的,那时候大家误以为品质问题是以此地点的付出引起,但实质上那几个费用非常小,在大家的行使场景不至于会推动品质难点。

人打麻将,倘诺后来的人也想搓黄金年代把碰碰运气,那么他必需等待直到麻将桌上的人走掉一个人。好,那正是归纳的功率信号计数机制,从本事角

3) public bool SignalAndWait(int millisecondsTimeout); 如若具备参预者都已经在钦定期间内完毕屏障,则为 true;否则为 false。

图片 3图片 4

2)当Configurewait(flase),则不实行线程上下文新闻的捕获,async方法中与await之后的代码实施时就非常小概获得await早先的线程的上下文音讯,在ASP.NET中最直白的震慑正是HttpConext.Current的值为null。

度上来讲它是概念了最多能够踏向入眼代码的线程数。

4) public int ParticipantCount { get; } 获取屏障中参与者的总和。

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {

            Thread t1 = new Thread(Run1);
            t1.Start();

            Thread t2 = new Thread(Run2);
            t2.Start();

            Console.Read();
        }

        //初始可以授予2个线程信号,因为第3个要等待前面的Release才能得到信号
        static Semaphore sem = new Semaphore(3, 10, "命名Semaphore");

        static void Run1()
        {
            sem.WaitOne();

            Console.WriteLine("进程:"   Process.GetCurrentProcess().Id   "  我是Run1"   DateTime.Now.TimeOfDay);
        }

        static void Run2()
        {
            sem.WaitOne();

            Console.WriteLine("进程:"   Process.GetCurrentProcess().Id   "  我是Run2"   DateTime.Now.TimeOfDay);
        }
    }
}

     但是Countdown伊夫nt更牛X之处在于大家能够动态的转移“时限信号计数”的大小,比方一立即可以知道容纳8个线程,一下又4个,一下又13个,

5) public long CurrentPhaseNumber { get; internal set; }获取屏障的前段时间阶段编号。

Program

诸有此类做有何低价呢?照旧传承上风流浪漫篇小说所说的,例如三个任务须要加载1w条数据,那么恐怕现身这种意况。

6)public int ParticipantsRemaining { get; }获取屏障中一向不在这里时此刻阶段发出复信号的加入者的数据。每当新阶段初阶时,那一个值等于ParticipantCount ,每当有参与者调用那特性辰时,其减意气风发。

图片 5

 

注意:

一贯运营五次bin目录的exe文件,就能够窥见最四只可以输出3个。

加载User表:         依照user表的数据量,我们须求开5个task。

1) 每当屏障(Barrier实例)接纳到来自具有参预者的非数字信号之后,屏障就能递增其等级数,运营构造函数中钦赐的动作,并且毁灭阻塞每三个参与者。

Semaphore能够节制可同期做客某一能源或财富池的线程数。

加载Product表:    产品表数据相对相当多,计算之后要求开8个task。

2)Barrier使用完要调用Dispose()方法释放能源

        塞马phore类在内部维护一个计数器,当三个线程调用Semaphore对象的Wait连串措施时,此计数器减生龙活虎,只要计数器如故贰个正数,线程就不会阻塞。当计数器减到0时,再调用Semaphore对象Wait类别措施的线程将被封堵,直到有线程调用塞马phore对象的Release()方法扩张计数器值时,才有超级大可能率打消阻塞状态。

加载order表:       由于自家的网址订单增加,计算之后需求开11个task。

3.CountdownEvent

 

 

珍视成员:

事必躬亲表达:
体育场合都配置有多少台公用Computer供读者查询新闻,当某日读者超多时,必需排队等候。UseLibraryComputer实例用多线程模拟了几人使用多台Computer的经过

先前的稿子也说了,大家需求协和task在多阶段加载数据的三头难点,那么哪些作答这里的5,8,12,辛亏,CountdownEvent给我们提供了

1) public int InitialCount { get; } 获取设置事件时最早的数字信号数。

图片 6图片 7

可以动态修改的解决方案。

1) public CountdownEvent(int initialCount);

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        //图书馆拥有的公用计算机  
        private const int ComputerNum = 3;
        private static Computer[] LibraryComputers;
        //同步信号量  
        public static Semaphore sp = new Semaphore(ComputerNum, ComputerNum);

        static void Main(string[] args)
        {
            //图书馆拥有ComputerNum台电脑  
            LibraryComputers = new Computer[ComputerNum];
            for (int i = 0; i < ComputerNum; i  )
                LibraryComputers[i] = new Computer("Computer"   (i   1).ToString());
            int peopleNum = 0;
            Random ran = new Random();
            Thread user;
            System.Console.WriteLine("敲任意键模拟一批批的人排队使用{0}台计算机,ESC键结束模拟……", ComputerNum);
            //每次创建若干个线程,模拟人排队使用计算机  
            while (System.Console.ReadKey().Key != ConsoleKey.Escape)
            {
                peopleNum = ran.Next(0, 10);
                System.Console.WriteLine("n有{0}人在等待使用计算机。", peopleNum);

                for (int i = 1; i <= peopleNum; i  )
                {
                    user = new Thread(UseComputer);
                    user.Start("User"   i.ToString());
                }
            }
        }

        //线程函数  
        static void UseComputer(Object UserName)
        {
            sp.WaitOne();//等待计算机可用  

            //查找可用的计算机  
            Computer cp = null;
            for (int i = 0; i < ComputerNum; i  )
                if (LibraryComputers[i].IsOccupied == false)
                {
                    cp = LibraryComputers[i];
                    break;
                }
            //使用计算机工作  
            cp.Use(UserName.ToString());

            //不再使用计算机,让出来给其他人使用  
            sp.Release();
        }
    }

    class Computer
    {
        public readonly string ComputerName = "";
        public Computer(string Name)
        {
            ComputerName = Name;
        }
        //是否被占用  
        public bool IsOccupied = false;
        //人在使用计算机  
        public void Use(String userName)
        {
            System.Console.WriteLine("{0}开始使用计算机{1}", userName, ComputerName);
            IsOccupied = true;
            Thread.Sleep(new Random().Next(1, 2000)); //随机休眠,以模拟人使用计算机  
            System.Console.WriteLine("{0}结束使用计算机{1}", userName, ComputerName);
            IsOccupied = false;
        }
    }
}

 

2) public bool Signal();向 CountdownEvent 注册能量信号,相同的时候减小CurrentCount的值。

Program

  1 using System.Collections.Concurrent;
  2 using System.Threading.Tasks;
  3 using System;
  4 using System.Diagnostics;
  5 using System.Collections.Generic;
  6 using System.Linq;
  7 using System.Threading;
  8 
  9 class Program
 10 {
 11     //默认的容纳大小为“硬件线程“数
 12     static CountdownEvent cde = new CountdownEvent(Environment.ProcessorCount);
 13 
 14     static void Main(string[] args)
 15     {
 16         //加载User表需要5个任务
 17         var userTaskCount = 5;
 18 
 19         //重置信号
 20         cde.Reset(userTaskCount);
 21 
 22         for (int i = 0; i < userTaskCount; i  )
 23         {
 24             Task.Factory.StartNew((obj) =>
 25             {
 26                 LoadUser(obj);
 27             }, i);
 28         }
 29 
 30         //等待所有任务执行完毕
 31         cde.Wait();
 32 
 33         Console.WriteLine("nUser表数据全部加载完毕!n");
 34 
 35         //加载product需要8个任务
 36         var productTaskCount = 8;
 37 
 38         //重置信号
 39         cde.Reset(productTaskCount);
 40 
 41         for (int i = 0; i < productTaskCount; i  )
 42         {
 43             Task.Factory.StartNew((obj) =>
 44             {
 45                 LoadProduct(obj);
 46             }, i);
 47         }
 48 
 49         cde.Wait();
 50 
 51         Console.WriteLine("nProduct表数据全部加载完毕!n");
 52 
 53         //加载order需要12个任务
 54         var orderTaskCount = 12;
 55 
 56         //重置信号
 57         cde.Reset(orderTaskCount);
 58 
 59         for (int i = 0; i < orderTaskCount; i  )
 60         {
 61             Task.Factory.StartNew((obj) =>
 62             {
 63                 LoadOrder(obj);
 64             }, i);
 65         }
 66 
 67         cde.Wait();
 68 
 69         Console.WriteLine("nOrder表数据全部加载完毕!n");
 70 
 71         Console.WriteLine("n(*^__^*) 嘻嘻,恭喜你,数据全部加载完毕n");
 72 
 73         Console.Read();
 74     }
 75 
 76     static void LoadUser(object obj)
 77     {
 78         try
 79         {
 80             Console.WriteLine("当前任务:{0}正在加载User部分数据!", obj);
 81         }
 82         finally
 83         {
 84             cde.Signal();
 85         }
 86     }
 87 
 88     static void LoadProduct(object obj)
 89     {
 90         try
 91         {
 92             Console.WriteLine("当前任务:{0}正在加载Product部分数据!", obj);
 93         }
 94         finally
 95         {
 96             cde.Signal();
 97         }
 98     }
 99 
100     static void LoadOrder(object obj)
101     {
102         try
103         {
104             Console.WriteLine("当前任务:{0}正在加载Order部分数据!", obj);
105         }
106         finally
107         {
108             cde.Signal();
109         }
110     }
111 }

3) public void Reset(int count);将 System.Threading.Countdown伊夫nt.InitialCount 属性重新恢复设置为钦点值。

 

 

注意:

2、SemaphoreSlim类

图片 8

不容置疑要保障每种参预职业的线程都调用了Signal,假使有最少三个未曾调用,那么职责会永久阻塞。所以常常在finally块中调用Signal是个好习于旧贯。

     在.net 4.0事先,framework中有二个重量级的Semaphore,能够跨进程同步,塞马phoreSlim轻量级不行,msdn对它的表明为:限定可同不时间做客某一能源或财富池的线程数。

大家看来有八个体贴措施:Wait和Signal。每调用贰回Signal相当于麻将桌子上走了一人,直到全数人都搓过麻将wait才给放行,这里雷同要

4.ManualResetEvent与ManualResetEventSlim

图片 9图片 10

留意约等于“超时“难题的存在性,尤其是在并行计算中,轻量等级给大家提供了”打消标识“的机制,那是在重量品级中一纸空文的,比方下边包车型客车

马努alReset伊芙nt:可达成跨进度或AppDomain的一块儿。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static SemaphoreSlim slim = new SemaphoreSlim(Environment.ProcessorCount, 12);

        static void Main(string[] args)
        {
            for (int i = 0; i < 12; i  )
            {
                Task.Factory.StartNew((obj) =>
                {
                    Run(obj);
                }, i);
            }
            Console.Read();
        }

        static void Run(object obj)
        {
            slim.Wait();
            Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj);
            //这里busy3s中
            Thread.Sleep(3000);
            slim.Release();
        }
    }
}

重载public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken),具体应用能够看前后生可畏篇文章的牵线。

珍视成员:

Program

 

1)public bool Reset();将事件境况设置为非终止状态,导致线程阻止,重返值提示操作是或不是成功。

近似,幸免死锁的意况,大家须求知道”超时和收回标识“的消除方案,像SemaphoreSlim这种定死的”线程诉求范围“,其实是下落了增加性,使用需稳重,在认为有必要的时候利用它

二:SemaphoreSlim

2)public bool Set();将事件情况设置为小憩景况,允许贰个或八个等待线程继续,重回值提醒操作是还是不是中标。

注:Semaphore类是SemaphoreSlim类的老版本,该版本采纳纯粹的木本时间(kernel-time)方式。

     在.net 4.0事先,framework中有二个重量级的Semaphore,人家能够跨进程同步,咋轻量级不行,msdn对它的表达为:节制可同不经常候做客

马努alReset伊夫ntSlim:不可动用于跨进度的一块儿。

    SemaphoreSlim类不应用Windows内核实信号量,并且也不扶持进度间一块。所以在跨程序同步的气象下能够运用Semaphore

某一资源或财富池的线程数。关于它的轻重级demo,笔者的上一个五种有示范,你也足以知道为CountdownEvent是 SemaphoreSlim的效应加

最首要成员:

 

强版,好了,举一个轻量级使用的例证。

1) public bool IsSet { get; }获取是或不是设置了事件。

3、CountdownEvent类

 1 using System.Collections.Concurrent;
 2 using System.Threading.Tasks;
 3 using System;
 4 using System.Diagnostics;
 5 using System.Collections.Generic;
 6 using System.Linq;
 7 using System.Threading;
 8 
 9 class Program
10 {
11     static SemaphoreSlim slim = new SemaphoreSlim(Environment.ProcessorCount, 12);
12 
13     static void Main(string[] args)
14     {
15         for (int i = 0; i < 12; i  )
16         {
17             Task.Factory.StartNew((obj) =>
18             {
19                 Run(obj);
20             }, i);
21         }
22 
23         Console.Read();
24     }
25 
26     static void Run(object obj)
27     {
28         slim.Wait();
29 
30         Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj);
31 
32         //这里busy3s中
33         Thread.Sleep(3000);
34 
35         slim.Release();
36     }
37 }

2) public void Reset();将事件处境设置为非终止状态,从而致使线程受阻,重返值提示操作是还是不是中标。

     这种利用非数字信号状态的联手基元特别切合在动态的fork,join的意况,它使用“功率信号计数”的主意,就比如那样,三个麻将桌只好宽容4个人打麻将,假若后来的人也想搓大器晚成把碰碰运气,那么他必得等待直到麻将桌子的上面的人走掉一人。好,那就是简轻巧单的时域信号计数机制,从技艺角度上的话它是概念了最多能够步入第一代码的线程数。

 

3)public bool Set();将事件景况设置为安息情状,允许二个或多少个等待线程继续,重回值提示操作是还是不是中标。

     但是Countdown伊芙nt更牛X之处在于我们得以动态的转移“随机信号计数”的大小,举例一弹指间能力所能达到容纳8个线程,一下又4个,一下又十个,那样做有哪些实惠吗?比如三个职务需求加载1w条数据,那么大概现身这种意况。

图片 11

4)public void Wait();阻止当前线程,直到设置了方今 马努alResetEventSlim 结束。

例如:

意气风发律,幸免死锁之处,我们要求通晓”超时和撤除标志“的建设方案,像SemaphoreSlim这种定死的”线程乞求范围“,其实是降低了扩大性,

5) public void Dispose();释放财富。

加载User表:         依据user表的数据量,大家必要开5个task。

据此说,试水有高风险,使用需稳重,在以为有供给的时候使用它。

6)public ManualResetEventSlim(bool initialState, int spinCount);

加载Product表:    产品表数据绝相比超级多,计算之后需求开8个task。

 

5.Semaphore与SemaphoreSlim

加载order表:       由于自个儿的网址订单增加,计算之后供给开13个task。

三: ManualResetEventSlim

Semaphore:可实现跨进度或AppDomain的贰只,可应用WaitHandle操作依次减少时限信号量的计数。

图片 12图片 13

     相信它的重量品级我们都清楚是马努alReset,而那些轻量等第采纳的是"自旋等待“ ”内核等待“,也等于说先使用”自旋等待的秘籍“等待,

第百分之十员:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        //默认的容纳大小为“硬件线程“数
        static CountdownEvent cde = new CountdownEvent(Environment.ProcessorCount);

        static void LoadUser(object obj)
        {
            try
            {
                Console.WriteLine("ThreadId={0};当前任务:{1}正在加载User部分数据!", Thread.CurrentThread.ManagedThreadId, obj);
            }
            finally
            {
                cde.Signal();
            }
        }

        static void LoadProduct(object obj)
        {
            try
            {
                Console.WriteLine("ThreadId={0};当前任务:{1}正在加载Product部分数据!", Thread.CurrentThread.ManagedThreadId, obj);
            }
            finally
            {
                cde.Signal();
            }
        }

        static void LoadOrder(object obj)
        {
            try
            {
                Console.WriteLine("ThreadId={0};当前任务:{1}正在加载Order部分数据!", Thread.CurrentThread.ManagedThreadId, obj);
            }
            finally
            {
                cde.Signal();
            }
        }

        static void Main(string[] args)
        {
            //加载User表需要5个任务
            var userTaskCount = 5;
            //重置信号
            cde.Reset(userTaskCount);
            for (int i = 0; i < userTaskCount; i  )
            {
                Task.Factory.StartNew((obj) =>
                {
                    LoadUser(obj);
                }, i);
            }
            //等待所有任务执行完毕
            cde.Wait();
            Console.WriteLine("nUser表数据全部加载完毕!n");

            //加载product需要8个任务
            var productTaskCount = 8;
            //重置信号
            cde.Reset(productTaskCount);
            for (int i = 0; i < productTaskCount; i  )
            {
                Task.Factory.StartNew((obj) =>
                {
                    LoadProduct(obj);
                }, i);
            }
            cde.Wait();
            Console.WriteLine("nProduct表数据全部加载完毕!n");

            //加载order需要12个任务
            var orderTaskCount = 12;
            //重置信号
            cde.Reset(orderTaskCount);
            for (int i = 0; i < orderTaskCount; i  )
            {
                Task.Factory.StartNew((obj) =>
                {
                    LoadOrder(obj);
                }, i);
            }
            cde.Wait();
            Console.WriteLine("nOrder表数据全部加载完毕!n");

            Console.WriteLine("n(*^__^*) 嘻嘻,恭喜你,数据全部加载完毕n");
            Console.Read();
        }
    }
}

以致于另二个职责调用set方法来释放它。假使迟迟等不到释放,那么职分就能够进来基于内核的守候,所以说只要我们掌握等待的光阴超短,采

1)public Semaphore(int initialCount, int maximumCount);

Program

用轻量级的版本会具有越来越好的属性,原理大概有如此,下边举个小例子。

2)public int Release();退出时限信号量并重返前贰个计数。

大家看出有三个重大方法:Wait和Signal。每调用贰回Signal也正是麻将桌子上走了一个人,直到全部人都搓过麻将wait才给放行,这里近似要介怀约等于“超时“难点的存在性,特别是在并行总结中,轻量品级给大家提供了”撤除标志“的编写制定,那是在重量等级中海市蜃楼的

 1 using System.Collections.Concurrent;
 2 using System.Threading.Tasks;
 3 using System;
 4 using System.Diagnostics;
 5 using System.Collections.Generic;
 6 using System.Linq;
 7 using System.Threading;
 8 
 9 class Program
10 {
11     //2047:自旋的次数
12     static ManualResetEventSlim mrs = new ManualResetEventSlim(false, 2047);
13 
14     static void Main(string[] args)
15     {
16 
17         for (int i = 0; i < 12; i  )
18         {
19             Task.Factory.StartNew((obj) =>
20             {
21                 Run(obj);
22             }, i);
23         }
24 
25         Console.WriteLine("当前时间:{0}我是主线程{1},你们这些任务都等2s执行吧:n",
26         DateTime.Now,
27         Thread.CurrentThread.ManagedThreadId);
28         Thread.Sleep(2000);
29 
30         mrs.Set();
31 
32         Console.Read();
33     }
34 
35     static void Run(object obj)
36     {
37         mrs.Wait();
38 
39         Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj);
40     }
41 }

3)public virtual bool WaitOne(); 阻止当前线程,直到当前 System.Threading.WaitHandle 收到频限信号。 即便当前实例收到实信号,则为 true。 假使当前实例恒久收不到复信号,则 System.Threading.WaitHandle.WaitOne(System.Int32,System.Boolean)永不重返。

注:借使调用Signal()未有达到钦赐的次数,那么Wait()将直接等候,请确认保证使用各种线程达成后都要调用Signal方法。

 

注意:

 

图片 14

使用完塞马phore马上调用Dispose()方法释放财富。

 

SemaphoreSlim:不可完毕跨进度或AppDomain的一头,不可利用WaitHandle操作递减功率信号量的计数。

要害成员:

1)public SemaphoreSlim(int initialCount, int maxCount);

2)public int CurrentCount { get; } 获取将同意步向System.Threading.SemaphoreSlim 的线程的数目。

3)public int Release();退出 System.Threading.SemaphoreSlim 一次。

4)public void Wait();阻止当前线程,直至它可进入System.Threading.SemaphoreSlim 结束。

5)public WaitHandle AvailableWaitHandle { get; }重回一个可用来在随机信号量上等候的 System.Threading.WaitHandle。

注意:

动用完塞马phoreSlim立刻调用Dispose()方法释放能源。

6.SpinLock:自旋锁,对SpinWait的包装

根本成员:

1)public void Enter(ref bool lockTaken); 选取可相信的不二等秘书诀获取锁,这样,即便在点子调用中发出特别的图景下,都能接受可相信的方法检查 lockTaken 以分明是否已获得锁。

2)public void Exit(bool useMemoryBarrier);释放锁

说明:

1)不要将SpinLock表明为只读字段。

2)确认保证每趟职务完结后都放出锁。

7.SpinWait:基于自旋的守候

器重成员:

1)public static void SpinUntil(Func<bool> condition);在钦赐条件得到满意从前自旋。

2)public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout);在钦赐条件获得满意或内定超时晚点事先自旋。

说明:

1)适用境况:等待某些条件满足急需的光阴超短,而且不期望爆发昂贵的上下文切换。

2)内部存款和储蓄器开销十分小。其是四个结构体,不会发出不须要的内部存款和储蓄器成本。

3)如若自旋时间过长,SpinWait会让出底层线程的时间片并触发上下文切换。

8.Look:互斥锁

说明:

1)通过动用lock关键字能够拿走三个指标的互斥锁。

2)使用lock,那会调用System.Threading.Monitor.Enter(object obj, ref bool lockTaken)和System.Threading.Monitor.Exit(object obj)方法。

3)不要对值类型使用Lock

4)避免锁定类的表面临象,幸免跨成员或类的界线获得和自由贰个锁,防止获得锁的时候调用未知代码。

9.Monitor

注重成员:

1)public static void Enter(object obj, ref bool lockTaken);获取内定对象上的排他锁,并机关安装二个值,提醒是不是取得了该锁。

2)public static void Exit(object obj);释放内定对象上的排他锁。

3)public static void TryEnter(object obj, int millisecondsTimeout, ref bool lockTaken);在钦赐的微秒数中,尝试获得内定对象上的排他锁,并自行安装叁个值,提醒是不是拿走了该锁。

说明:

1)不要对值类型使用Monitor。

2)防止锁定类的外表对象,防止跨成员或类的边界获得和自由叁个锁,幸免获得锁的时候调用未知代码。

10.volatile修饰符

作用:

当分享变量被差异的线程访问和更新且未有锁和原子操作的时候,最新的值总能在分享变量中表现出来。

注意:

1)能够将以此修饰符用于类和struct的字段,但无法声称使用volatile关键字的一些变量。

2)Volatile可修饰的类型为:整型,bool,带有整型的枚举,援用类型,推到为引用类型的泛型类型,不安全上下文中的指针类型以致代表指针也许句柄的阳台相关项目。

11.Interlocked:为多职分或线程分享的变量提供原子操作

主要成员:

1)public static int Increment(ref int location);以原子操作的样式依次增加钦命变量的值并存款和储蓄结果。

2)public static int Add(ref int location1, int value);对多个 32位整数举办求和并用和替换第二个整数,上述操作作为一个原子操作完成。

3)public static float CompareExchange(ref float location1, float value, float comparand); 相比较三个单精度浮点数是还是不是等于,要是相等,则替换此中一个值。

4)public static int Decrement(ref int location);以原子操作的花样依次减少钦命变量的值并存款和储蓄结果。

注意:

最大的补益:费用低,功效高。

 

12 使用格局

1)Barrier

 1 public static void BarrierTest1()
 2 {
 3             //构造函数的参数participantCount表示参与者的数量。
 4             //注意:父线程也是一个参与者,所以两个任务,但是Barrier的participantCount为3
 5             //注意:无法保证任务1和任务2完成的先后顺序。
 6             //Barrier(int participantCount, Action<Barrier> postPhaseAction);也可使 用此方法
 7             //当所有参与者都已到达屏障后,执行要处理的任务,即对两个任务产生的数据统一处理的过程可放在此处执行。
 8             using (Barrier bar = new Barrier(3))
 9             {
10                 Task.Factory.StartNew(() =>
11                 {
12 
13                     //具体业务
14 
15                     //当业务完成时,执行下面这行代码;发出信号,表明任务已完成,并等待其他参与者
16                     bar.SignalAndWait();
17 
18                 });
19 
20                 Task.Factory.StartNew(() =>
21                 {
22 
23                     //具体业务
24 
25                     //当业务完成时,执行下面这行代码;发出信号,表明任务已完成,并等待其他参与者
26                     bar.SignalAndWait();
27 
28                 });
29 
30                 //保证上面两个任务都能完成才执行bar.SignalAndWait();这一句之后的代码
31                 bar.SignalAndWait();
32                 //当上述两个任务完成后,对两个任务产生的数据进行统一处理。
33 
34             }
35 
36         }
37 
38         public static void BarrierTest2()
39         {
40             //构造函数的参数participantCount表示参与者的数量。
41             using (Barrier bar = new Barrier(3))
42             {
43                 Task.Factory.StartNew(() =>
44                 {
45 
46                     //具体业务
47 
48                     //当业务完成时,执行下面这行代码;移除一个参与者
49                     //注意:bar.SignalAndWait();与bar.RemoveParticipant();可以混用
50                     bar.RemoveParticipant();
51 
52                 });
53 
54                 Task.Factory.StartNew(() =>
55                 {
56 
57                     //具体业务
58 
59                     //当业务完成时,执行下面这行代码;移除一个参与者
60                     bar.RemoveParticipant();
61 
62                 });
63 
64                 bar.SignalAndWait();
65                 //当上述两个任务完成后,对两个任务产生的数据进行统一处理。
66             }
67 }

2)CountdownEvent

 1 public static void CountdownEventTest()
 2 {
 3             //注意初始化信号数等于并行的任务数
 4             int initialCount = N;
 5             using (CountdownEvent cd = new CountdownEvent(initialCount))
 6             {
 7                 //多个并行任务,完成一个减少一个信号
 8                 for (int i = 0; i < N; i  )
 9                 {
10                     Task.Factory.StartNew(() => 
11                     {
12                         try
13                         {
14                             //真正的业务
15                         }
16                         finally
17                         {
18                             //确保不论何种情况都能减少信号量,防止死循环
19                             cd.Signal();
20                         }
21                     });
22                 }
23 
24                 //等待上述多个任务执行完毕
25                 cd.Wait();
26             }
27 }

3)ManualResetEvent与ManualResetEventSlim

 1 public static void ManualResetEventTest()
 2 {
 3             ManualResetEvent mre = new ManualResetEvent(false);
 4             ManualResetEvent mre1 = new ManualResetEvent(false);
 5 
 6             try
 7             {
 8                 Task.Factory.StartNew(() =>
 9                 {
10                     //业务
11                     mre.Set();
12                 });
13 
14                 Task.Factory.StartNew(() =>
15                 {
16                     mre.WaitOne();
17 
18                     //使用任务1的数据
19                     
20                     mre1.Set();
21 
22                 });
23 
24                 //等待任务全部执行完
25                 mre1.WaitOne();
26             }
27             finally
28             {
29                 mre.Dispose();
30                 mre1.Dispose();
31             }
32         }
33         //注意:本示例并不是一个最佳实践,目的在于演示ManualResetEventSlim
34         //当没有更好的协调机制时,可考虑使用本示例
35         public static void ManualResetEventSlimTest1()
36         {
37             ManualResetEventSlim mreslim = new ManualResetEventSlim();
38             ManualResetEventSlim mreslim1 = new ManualResetEventSlim();
39             try
40             {
41                 Task.Factory.StartNew(() =>
42                 {
43                     mreslim.Set();
44 
45                     //业务
46 
47                     mreslim.Reset();
48 
49                 });
50 
51                 Task.Factory.StartNew(() =>
52                 {
53                     //当mreslim.Set()被调用时,mreslim.Wait()立即返回,即解除阻塞。
54                     mreslim.Wait();
55                     //直到mreslim.Reset()被调用,循环才会结束
56                     while (mreslim.IsSet)
57                     {
58                         //业务
59                     }
60                     mreslim1.Set();
61                 });
62 
63                 //等待第二个任务完成
64                 mreslim1.Wait();
65             }
66             finally
67             {
68                 mreslim.Dispose();
69                 mreslim1.Dispose();
70             }
71 }

4)Semaphore与SemaphoreSlim

 1 public static void SemaphoreSlimTest()
 2 {
 3             int initialCount = 10;//可以是其他值
 4             List<string> list = new List<string>();
 5             var tasks = new Task[initialCount];
 6        //如果使用Semaphore,实例化的时候,那么最少要传递两个参数,信号量的初始请求数和信号量的最大请求数
 7             using(SemaphoreSlim ssl = new SemaphoreSlim(initialCount))
 8             {
 9                 for (int i = 0; i < initialCount; i  )
10                 {
11                     int j = i;
12                     tasks[j] = Task.Factory.StartNew(() =>
13                     {
14                         try
15                         {
16                             //等待,直到进入SemaphoreSlim为止
17                  //如果使用Semaphore,应调用WaitOne
18                             ssl.Wait();
19                             //直到进入SemaphoreSlim才会执行下面的代码
20                             list.Add("" j);//可将这部分替换成真实的业务代码
21                         }
22                         finally
23                         {
24                             ssl.Release();
25                         }
26                     });
27                 }
28                 //注意一定要在using块的最后阻塞线程,直到所有的线程均处理完任务
29                 //如果没有等待任务全部完成的语句,会导致SemaphoreSlim资源被提前释放。
30                 Task.WaitAll(tasks);
31             }          
32 }

5)SpinLock

 1 public static void SpinLockTest()
 2 {
 3             bool lockTaken = false;
 4             SpinLock sl = new SpinLock(true);
 5             try
 6             {
 7                 //获得锁
 8                 //如果不能获得锁,将会等待并不断检测锁是否可用
 9                 //获得锁后,lockTaken为true,此行代码之后的部分才会开始运行
10                 sl.Enter(ref lockTaken);
11 
12                 //或使用含有超时机制的TryEnter方法
13                 //sl.TryEnter(1000,ref lockTaken);
14                 //然后抛出超时异常
15                 //if (!lockTaken)
16                 //{
17                 //    throw new TimeoutException("超时异常");
18                 //}
19 
20                 //真正的业务。。。
21                 
22             }
23             finally
24             {
25                 if (lockTaken)
26                 {
27                     //释放锁
28                     //SpinLock没有使用内存屏障,因此设成false
29                     sl.Exit(false);
30                 }
31             }                        
32 }

6)SpinWait

 1 public static void SpinWaitTest()
 2 {
 3             bool isTrue = false;
 4             //任务一,处理业务,成功将isTrue设置为true
 5             Task.Factory.StartNew(() => 
 6             {
 7                 //处理业务,返回结果result指示是否成功
 8                 bool result = ...;
 9                 if (result)
10                 {
11                     isTrue = true;
12                 }
13             });
14 
15             //可设定等待时间,如果超时,则向下执行
16             Task.Factory.StartNew(() => {
17                 SpinWait.SpinUntil(()=>isTrue,10000);
18                 //真正的业务
19             });
20 }

7) Look

 1 下面两段代码是等价的。
 2 lock (Object)
 3 {
 4        //do something
 5 }
 6 
 7 //等价代码
 8 bool lockTaken = false;
 9 try
10 {
11     Monitor.Enter(object,lockTaken);
12      //do something
13 }
14 finally
15 {
16      if(lockTaken)
17      {
18             Monitor.Exit(object);
19        }
20 }

8)Interlocked

 1 public static void InterlockedTest()
 2 {
 3             Task[] tasks = new Task[10];
 4             long j = 0;
 5             for(int i=0;i<10;i  )
 6             {
 7                 int t = i;
 8                 tasks[t] = Task.Factory.StartNew(()=>
 9                 {
10                 //以安全的方式递增j
11                     Interlocked.Increment(ref j);
12                 });
13             }
14             Task.WaitAll(tasks);           
15 }

转载与援用请申明出处。

时间匆忙,水平有限,如有不当之处,应接指正。

 

本文由星彩网app下载发布于计算机编程,转载请注明出处:限定使用,同步机制

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。