联机机制,限量使用

题材抽象:当某1能源一样时刻同意早晚数量的线程使用的时候,须要有个机制来阻塞多余的线程,直到能源重复变得可用。
线程同步方案:Semaphore、SemaphoreSlim、CountdownEvent
方案性子:限量供应;除全体者外,别的人无条件等待;先到先得,尚未先后顺序

当三个职务或线程并行运营时,难以制止的对少数有限的财富进行并发的走访。能够思量选拔实信号量来举办那上边的支配(System.Threading.Semaphore)是表示三个Windows内核的信号量对象。如若预测等待的年华较短,能够思量使用SemaphoreSlim,它则带来的成本越来越小。.NetFrameWork中的时域信号量通过跟踪进入和离开的任务或线程来协调对能源的访问。信号量必要掌握能源的最大数据,当一个职责进入时,财富计数器会被减一,当计数器为0时,假若有义务访问能源,它会被打断,直到有任务离开截止。
假若须求有跨进度或AppDomain的1块时,能够缅想选取Semaphore。塞马phore是取得的Windows
内核的功率信号量,所以在任何种类中是立见成效的。它至关心注重要的接口是Release和WaitOne,使用的法子和SemaphoreSlim是一模1样的。
功率信号量Semaphore是其余一个CLRubicon中的内核同步对象。在.net中,类Semaphore封装了这一个指标。与行业内部的排他锁对象(Monitor,Mutex,SpinLock)分歧的是,它不是1个排他的锁对象,它与SemaphoreSlim,ReaderWriteLock等同样允许两个少于的线程同时访问共享内部存储器能源。

   

1.简介

1、Semaphore类
     
用于控制线程的拜访数量,暗许的构造函数为initialCount和maximumCount,表示私下认可设置的非信号量个数和最大实信号量个数。当您WaitOne的时候,实信号量自减,当Release的时候,时域信号量自增,然则当时域信号量为0的时候,后续的线程就不可能获得WaitOne了,所以必须等待先前的线程通过Release来释放。

Semaphore就就像二个栅栏,有早晚的体量,当在那之中的线程数量到达安装的最大值时候,就从未线程能够进入。然后,假若贰个线程工作形成以往出来了,那下1个线程就足以进去了。Semaphore的WaitOne或Release等操作分别将活动地递减大概递增随机信号量的方今计数值。当线程试图对计数值已经为0的非能量信号量执行WaitOne操作时,线程将卡住直到计数值大于0。在构造Semaphore时,最少要求2个参数。实信号量的发端体积和最大的体积。

   
 承接上1篇,大家继续说下.net四.0中的同步机制,是的,当出现了并行计算的时候,轻量级别的二头机制应运而生,在实信号量那壹块

新的轻量级同步原语:Barrier,Countdown伊夫nt,马努alReset伊夫ntSlim,SemaphoreSlim,SpinLock,SpinWait。轻量级同步原语只好用在贰个进程内。而相应的那些重量级版本支持跨进度的协同。

亚洲必赢官网 1亚洲必赢官网 2

塞马phore的WaitOne大概Release方法的调用大致会损耗一皮秒的系统时间,而优化后的SemaphoreSlim则供给大概四分一阿秒。在盘算中山大学量反复使用它的时候SemaphoreSlim照旧优势名高天下,加上SemaphoreSlim还加上了不少接口,越发有利于我们开展控制,所以在肆.0事后的八线程开发中,推荐使用SemaphoreSlim。SemaphoreSlim的贯彻如下:

并发了1多重的轻量级,今日前仆后继介绍上面包车型客车二个数字信号量 Countdown伊夫nt,SemaphoreSlim,马努alReset伊芙ntSlim。

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 */ }
        }
    }

 

第7%员

Program

SemaphoreSlim类有多少个私有字段很要紧,m_currentCount表示可用财富,如若m_currentCount>0老是调用Wait都会减壹,当m_currentCount<=0时再一次调用Wait方法就会卡住。每一遍调用Release方法m_currentCount都会加1.m_maxCount表示最大可用能源数,是在构造函数中钦命的。m_waitCount表示近期不通的线程数。TaskNode
m_asyncHead,m_asyncTail那3个变量重要用以异步方法。

一:CountdownEvent

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

在上述的主意中Release()方法约等于自增一个信号量,Release(5)自增两个随机信号量。而是,Release()到构造函数的首个参数maximumCount的值就不可能再自增了。

大家第一来探视Wait方法,那里还有它的异步版本WaitAsync。在Wait方法中第一检查m_currentCount是不是为0,假使是我们用SpinWait自旋10次;任意三遍Wait都亟待锁住m_lockObj对象,m_asyncHead
!=
null表示近期早就存在异步的指标,所以我们调用WaitAsync方法,假使未有那么大家调用WaitUntilCountOrTimeout方法,该办法在m_currentCount==0会卡住到到m_currentCount不为0恐怕逾期;看到WaitUntilCountOrTimeout方法中【if
(!Monitor.Wait(m_lockObj,
remainingWait米尔iseconds))】,就很明了Wait方法中【CancellationTokenRegistration
cancellationTokenRegistration =
cancellationToken.InternalRegisterWithoutEC(s_cancellationTokenCanceled伊夫ntHandler,
this)】存在的原故了,确实很巧妙【那里和马努alReset伊芙ntSlim相似】。今后我们回到WaitAsync方法,该方式也是第三检查m_currentCount是或不是大于0,大于直接重返。否者调用CreateAndAddAsyncWaiter成立一个Task<bool>【Task<bool>是一个链表结构】,借使未有撤废且超时超越-壹,那么就调用WaitUntilCountOrTimeoutAsync方法,该情势首先包装3个Task【var
waitCompleted = Task.WhenAny(asyncWaiter,
Task.Delay(millisecondsTimeout, cts.Token))】然后等待线程【await
waitCompleted.ConfigureAwait(false)】重回的是asyncWaiter恐怕另3个Delay的Task。假诺回去的不是asyncWaiter表明已经晚点供给调用RemoveAsyncWaiter,然后回来
await
asyncWaiter.ConfigureAwait(false),假设回去的是asyncWaiter,那么就调用Cancel方法。那么这里的asyncWaiter.ConfigureAwait(false)曾几何时退出了【只怕说不阻塞】,那即将看Release中的QueueWaiterTask方法了。

   
 那种应用时域信号状态的一块儿基元万分适合在动态的fork,join的场景,它应用“复信号计数”的格局,就比如那样,三个麻将桌只可以包容六个

二) 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减壹,那样感觉异步waiters优先获得资源。也不清楚笔者的明亮是不是正确?
一)当ConfigureAwait(true),代码由协助举行执行进入异步执行时,当前壹起施行的线程上下文新闻(比如HttpConext.Current,Thread.CurrentThread.CurrentCulture)就会被捕获并保留至SynchronizationContext中,供异步执行中动用,并且供异步执行到位今后(await之后的代码)的联合施行中选用(就算await之后是壹块实施的,然则爆发了线程切换,会在其余3个线程中实行「ASP.NET场景」)。这几个捕获当然是有代价的,当时大家误以为质量难点是以此地点的费用引起,但实际上这一个费用不大,在我们的运用场景不至于会带来质量难点。

亚洲必赢官网,人打麻将,假使后来的人也想搓一把碰碰运气,那么她必须等待直到麻将桌上的人走掉1位。好,那就是大概的能量信号计数机制,从技术角

三) public bool SignalAndWait(int millisecondsTimeout); 如若具有参预者都已在钦赐时间内落成屏障,则为
true;不然为 false。

亚洲必赢官网 3亚洲必赢官网 4

二)当Configurewait(flase),则不实行线程上下文新闻的捕获,async方法中与await之后的代码执行时就不恐怕获取await以前的线程的上下文音信,在ASP.NET中最直白的震慑就是HttpConext.Current的值为null。

度上来说它是概念了最多能够进入重点代码的线程数。

肆) 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之处在于大家得以动态的改变“数字信号计数”的分寸,比如1会儿力所能及容纳7个线程,一下又四个,一下又11个,

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

联机机制,限量使用。Program

如此做有何好处呢?还是承接上壹篇小说所说的,比如多少个义务必要加载1w条数据,那么大概出现那种情景。

6)public int ParticipantsRemaining {
get; }获取屏障中绝非在目前阶段发出时限信号的加入者的数量。每当新阶段开首时,那几个值等于ParticipantCount ,每当有参预者调用那性格寅时,其减壹。

亚洲必赢官网 5

 

注意:

一向运维两回bin目录的exe文件,就能窥见最八只可以输出二个。

加载User表:         依照user表的数据量,大家须求开多少个task。

1) 每当屏障(Barrier实例)接收到来自具备参加者的时域信号之后,屏障就会递增其等级数,运转构造函数中内定的动作,并且化解阻塞每一种参与者。

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

加载Product表:    产品表数据相对相比较多,计算之后供给开九个task。

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

       
Semaphore类在里边维护三个计数器,当1个线程调用塞马phore对象的Wait种类措施时,此计数器减1,只要计数器依旧四个正数,线程就不会堵塞。当计数器减到0时,再调用Semaphore对象Wait类别措施的线程将被封堵,直到有线程调用塞马phore对象的Release()方法扩展计数器值时,才有极大希望清除阻塞状态。

加载order表:       由于本人的网址订单增加,计算之后须求开10个task。

3.CountdownEvent

 

 

重在成员:

以身作则表达:
教室都布置有几多台公用总结机供读者查询消息,当某日读者相比多时,必须排队等候。UseLibraryComputer实例用十2线程模拟了多个人采取多台计算机的历程

先河的稿子也说了,大家要求协调task在多阶段加载数据的1头难题,那么如何作答那里的五,八,12,幸好,Countdown伊夫nt给我们提供了

一) 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();向 Countdown伊芙nt 注册复信号,同时减小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 }

叁) public void Reset(int count);将
System.Threading.Countdown伊芙nt.InitialCount
属性重新设置为内定值。

 

 

注意:

2、SemaphoreSlim类

亚洲必赢官网 8

肯定要保管每一种插手工作的线程都调用了Signal,假诺有最少贰个从没有过调用,那么任务会永远阻塞。所以1般在finally块中调用Signal是个好习惯。

     在.net
四.0此前,framework中有三个重量级的Semaphore,能够跨进程同步,SemaphoreSlim轻量级不行,msdn对它的解释为:限制可同时做客某一财富或能源池的线程数。

咱俩看看有三个根本情势:Wait和Signal。每调用1遍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),具体应用能够看前1篇小说的牵线。

第拾%员:

Program

 

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

1律,幸免死锁的景象,我们供给掌握”超时和撤回标记“的解决方案,像SemaphoreSlim那种定死的”线程请求范围“,其实是下落了扩充性,使用需谨慎,在认为有不可或缺的时候利用它

二:SemaphoreSlim

2)public bool
Set();将事件意况设置为停止景况,允许三个或七个等待线程继续,重返值提示操作是或不是中标。

注:Semaphore类是SemaphoreSlim类的老版本,该版本选择纯粹的基业时间(kernel-time)方式。

     在.net
四.0在此以前,framework中有3个重量级的Semaphore,人家能够跨过程同步,咋轻量级不行,msdn对它的演说为:限制可同时做客

马努alReset伊芙ntSlim:不可使用于跨进程的联手。

    SemaphoreSlim类不选取Windows内核时限信号量,而且也不援救进度间协同。所以在跨程序同步的场景下得以应用Semaphore

某1能源或能源池的线程数。关于它的份额级demo,我的上二个文山会海有示范,你也足以领略为Countdown伊芙nt是
SemaphoreSlim的功力加

重点成员:

 

强版,好了,举三个轻量级使用的例子。

壹) 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 }

二) public void
Reset();将事件意况设置为非终止状态,从而造成线程受阻,重临值提醒操作是还是不是成功。

   
 那种使用频域信号状态的共同基元非凡适合在动态的fork,join的场地,它使用“时域信号计数”的主意,就比如那样,五个麻将桌只好包容3人打麻将,借使后来的人也想搓一把碰碰运气,那么她必须等待直到麻将桌上的人走掉1位。好,那正是简不难单的时限信号计数机制,从技术角度上的话它是概念了最多能够进入重点代码的线程数。

 

3)public bool
Set();将事件情状设置为平息景况,允许3个或四个等待线程继续,重返值提醒操作是或不是成功。

   
 不过Countdown伊芙nt更牛X之处在于我们得以动态的转移“时限信号计数”的轻重缓急,比如1会儿可见容纳几个线程,一下又6个,一下又十个,那样做有怎么着利益吗?比如多个任务急需加载1w条数据,那么或然出现那种情状。

亚洲必赢官网 11

四)public void Wait();阻止当前线程,直到设置了脚下 ManualReset伊芙ntSlim
甘休。

例如:

相同,幸免死锁的景观,大家需求通晓”超时和注销标记“的化解方案,像SemaphoreSlim那种定死的”线程请求范围“,其实是下落了扩充性,

5) public void Dispose();释放能源。

加载User表:         依照user表的数据量,大家须要开伍个task。

因此说,试水有高危害,使用需谨慎,在认为有须要的时候使用它。

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

加载Product表:    产品表数据相对对比多,总结之后须求开7个task。

 

5.Semaphore与SemaphoreSlim

加载order表:       由于自家的网址订单拉长,总结之后必要开13个task。

三: ManualResetEventSlim

塞马phore:可完毕跨进度或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();
        }
    }
}

直到另2个职务调用set方法来释放它。假使迟迟等不到自由,那么职分就会进入基于内核的等候,所以说只要大家领略等待的年月比较短,采

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

Program

用轻量级的本子会怀有越来越好的性质,原理大约就这么,下边举个小例子。

2)public int Release();退出时域信号量并赶回前三个计数。

我们见到有五个基本点措施:Wait和Signal。每调用2次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 }

三)public virtual bool WaitOne(); 阻止当前线程,直到近期System.Threading.WaitHandle 收到复信号。 假诺当前实例收到实信号,则为 true。
如若当前实例永远收不到频域信号,则
System.Threading.WaitHandle.WaitOne(System.Int3贰,System.Boolean)永不重返。

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

 

注意:

 

亚洲必赢官网 14

动用完Semaphore马上调用Dispose()方法释放能源。

 

SemaphoreSlim:不可落成跨进度或AppDomain的同步,不可采纳WaitHandle操作递减实信号量的计数。

重在成员:

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

二)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的包装

最重要成员:

一)public void Enter(ref bool lockTaken);
选用可信的主意赢得锁,那样,就算在情势调用中产生尤其的事态下,都能运用可相信的章程检查
lockTaken 以明确是还是不是已收获锁。

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

说明:

一)不要将SpinLock证明为只读字段。

2)确认保证每一趟职务达成后都放出锁。

7.SpinWait:基于自旋的等待

首要成员:

一)public static void SpinUntil(Func<bool>
condition);在内定条件获得满意此前自旋。

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

说明:

一)适用情状:等待有个别条件满意急需的流年不够长,并且不期待发生昂贵的上下文切换。

贰)内部存款和储蓄器费用相当小。其是贰个结构体,不会发出不须求的内部存款和储蓄器开销。

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

8.Look:互斥锁

说明:

一)通过运用lock关键字能够赢得三个目的的互斥锁。

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

3)不要对值类型使用Lock

肆)防止锁定类的表面对象,幸免跨成员或类的边际获得和释放3个锁,防止获得锁的时候调用未知代码。

9.Monitor

驷不比舌成员:

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

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

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

说明:

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

2)制止锁定类的外部对象,制止跨成员或类的界限获得和刑释3个锁,制止得到锁的时候调用未知代码。

10.volatile修饰符

作用:

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

注意:

一)能够将以此修饰符用于类和struct的字段,但不能够声称使用volatile关键字的有个别变量。

二)Volatile可修饰的体系为:整型,bool,带有整型的枚举,引用类型,推到为引用类型的泛型类型,不安全上下文中的指针类型以及代表指针可能句柄的平台相关项目。

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

珍视成员:

一)public static int Increment(ref int
location);以原子操作的款型递增钦赐变量的值并存款和储蓄结果。

贰)public static int Add(ref int location壹, int value);对七个 33位整数进行求和并用和替换第四个整数,上述操作作为二个原子操作实现。

3)public static float CompareExchange(ref float location壹, float value,
float comparand);
比较八个单精度浮点数是还是不是等于,如若相等,则替换在那之中2个值。

四)public static int Decrement(ref int
location);以原子操作的款式递减钦赐变量的值并存款和储蓄结果。

注意:

最大的裨益:开支低,效用高。

 

1贰 使用情势

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 }

转载与引用请表明出处。

时刻仓促,水平有限,如有不当之处,欢迎指正。

 

网站地图xml地图