难点抽象:当某1能源一样时刻同意早晚数量的线程使用的时候,需求有个机制来阻塞多余的线程,直到财富再一次变得可用。
线程同步方案:Semaphore、SemaphoreSlim、CountdownEvent
方案本性:限量供应;除全部者外,别的人无条件等待;先到先得,尚未先后顺序

当多个任务或线程并行运维时,难以制止的对少数有限的财富举行并发的走访。能够设想使用功率信号量来举行那上边的支配(System.Threading.Semaphore)是表示七个Windows内核的时域信号量对象。假诺预测等待的年月较短,能够设想使用SemaphoreSlim,它则带来的开发越来越小。.NetFrameWork中的时限信号量通过跟踪进入和距离的职务或线程来协调对财富的拜会。确定性信号量要求领会能源的最大数目,当三个任务进入时,财富计数器会被减一,当计数器为0时,假设有任务访问财富,它会被堵塞,直到有职责离开甘休。
要是急需有跨进度或AppDomain的一块儿时,能够设想选择Semaphore。Semaphore是赢得的Windows
内核的功率信号量,所以在整个连串中是实惠的。它根本的接口是Release和WaitOne,使用的不二等秘书籍和SemaphoreSlim是平等的。
非实信号量Semaphore是其它四个CL奥迪Q5中的内核同步对象。在.net中,类Semaphore封装了那个目的。与正统的排他锁对象(Monitor,Mutex,SpinLock)不一样的是,它不是二个排他的锁对象,它与塞马phoreSlim,ReaderWriteLock等一样允许多少个少于的线程同时访问共享内部存款和储蓄器能源。

金沙注册送58 ,   

1.简介

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

Semaphore就接近多少个栅栏,有自然的体积,当其中的线程数量到达安装的最大值时候,就从不线程能够进入。然后,假设二个线程工作形成未来出来了,那下3个线程就足以进去了。塞马phore的WaitOne或Release等操作分别将机关地递减只怕递增频限信号量的最近计数值。当线程试图对计数值已经为0的连续信号量执行WaitOne操作时,线程将阻塞直到计数值大于0。在结构Semaphore时,最少须要贰个参数。实信号量的启幕容积和最大的体积。

   
 承接上1篇,大家继续说下.net4.0中的同步机制,是的,当出现了并行总括的时候,轻量级其他同台机制应运而生,在随机信号量这一块

新的轻量级同步原语:Barrier,Countdown伊芙nt,马努alReset伊夫ntSlim,SemaphoreSlim,SpinLock,SpinWait。轻量级同步原语只好用在3个经过内。而相应的那几个重量级版本匡助跨进程的一块。

金沙注册送58 1金沙注册送58 2

Semaphore的WaitOne恐怕Release方法的调用大概会损耗壹微秒的系统时间,而优化后的SemaphoreSlim则要求大致25%阿秒。在盘算中山大学量往往利用它的时候SemaphoreSlim依然优势明显,加上SemaphoreSlim还添加了诸多接口,越发有益于大家进行支配,所以在四.0过后的八线程开发中,推荐应用SemaphoreSlim。SemaphoreSlim的完成如下:

并发了一三种的轻量级,前几日接二连三介绍上边包车型地铁一个复信号量 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 */ }
        }
    }

 

首要成员

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那1个变量主要用来异步方法。

一:CountdownEvent

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

在上述的点子中Release()方法相当于自增二个功率信号量,Release(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_cancellationTokenCanceled伊夫ntHandler,
this)】存在的原由了,确实很抢眼【那里和马努alReset伊芙ntSlim相似】。以往大家回去WaitAsync方法,该措施也是第二检查m_currentCount是不是大于0,大于直接回到。否者调用CreateAndAddAsyncWaiter成立3个Task<bool>【Task<bool>是七个链表结构】,假设未有打消且超时超过-一,那么就调用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的场景,它应用“非时限信号计数”的秘籍,就比如那样,1个麻将桌只好包容多少个

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减一,那样感觉异步waiters优先得到能源。也不亮堂本人的知道是还是不是科学?
一)当ConfigureAwait(true),代码由1块实施进入异步执行时,当前一起执行的线程上下文新闻(比如HttpConext.Current,Thread.CurrentThread.CurrentCulture)就会被抓获并保存至SynchronizationContext中,供异步执行中应用,并且供异步执行到位以后(await之后的代码)的共同施行中接纳(纵然await之后是1块实施的,可是爆发了线程切换,会在其余二个线程中推行「ASP.NET场景」)。这一个捕获当然是有代价的,当时我们误以为质量难题是这么些地点的支付引起,但实则这些花费相当的小,在大家的利用场景不至于会拉动质量难题。

人打麻将,如若后来的人也想搓1把碰碰运气,那么她必须等待直到麻将桌上的人走掉一人。好,那就是简单的时域信号计数机制,从技术角

三) public bool SignalAndWait(int milliseconds提姆eout); 若是全部插足者都已在钦定时间内达到屏障,则为
true;否则为 false。

金沙注册送58 3金沙注册送58 4

二)当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之处在于我们能够动态的变更“非复信号计数”的尺寸,比如壹会儿能够容纳7个线程,一下又五个,一下又十一个,

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

Program

如此那般做有啥利益吗?依然承接上一篇小说所说的,比如七个义务急需加载壹w条数据,那么恐怕出现那种景色。

陆)public int ParticipantsRemaining {
get; }获取屏障中从不在此时此刻阶段发出功率信号的出席者的数额。每当新阶段起首时,这些值等于ParticipantCount ,每当有参加者调用那性格格时,其减壹。

金沙注册送58 5

 

1道机制,线程同步。注意:

直接运营五遍bin目录的exe文件,就能发现最八只可以输出二个。

加载User表:         依据user表的数据量,我们供给开伍个task。

一) 每当屏障(Barrier实例)接收到来自具备参加者的实信号未来,屏障就会递增其等级数,运转构造函数中钦点的动作,并且消除阻塞每二个到场者。

Semaphore能够界定可同时做客某一财富或财富池的线程数。

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

二)Barrier使用完要调用Dispose()方法释放财富

       
Semaphore类在内部维护三个计数器,当二个线程调用塞马phore对象的Wait类别措施时,此计数器减1,只要计数器照旧二个正数,线程就不会卡住。当计数器减到0时,再调用Semaphore对象Wait类别措施的线程将被封堵,直到有线程调用Semaphore对象的Release()方法扩张计数器值时,才有十分大概率裁撤阻塞状态。

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

3.CountdownEvent

 

 

主要成员:

示范表明:
体育场所都配置有多少台公用总计机供读者查询新闻,当某日读者比较多时,必须排队等候。UseLibraryComputer实例用二十八线程模拟了多少人选拔多台计算机的长河

原先的稿子也说了,大家必要协调task在多阶段加载数据的一路难点,那么哪些回答那里的五,8,1贰,幸亏,Countdown伊芙nt给我们提供了

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

金沙注册送58 6金沙注册送58 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类

金沙注册送58 8

早晚要保管每一个参预工作的线程都调用了Signal,假如有至少一个并未有调用,那么职责会永远阻塞。所以1般在finally块中调用Signal是个好习惯。

     在.net
四.0事先,framework中有三个重量级的Semaphore,能够跨进程同步,SemaphoreSlim轻量级不行,msdn对它的表达为:限制可同时做客某壹能源或能源池的线程数。

大家看出有五个重点格局:Wait和Signal。每调用1次Signal也正是麻将桌上走了一个人,直到全部人都搓过麻将wait才给放行,那里同样要

4.ManualResetEvent与ManualResetEventSlim

金沙注册送58 9金沙注册送58 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

 

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

如出一辙,幸免死锁的状态,大家必要理解”超时和撤回标记“的化解方案,像SemaphoreSlim那种定死的”线程请求范围“,其实是降低了扩充性,使用需谨慎,在认为有须要的时候使用它

二:SemaphoreSlim

②)public bool
Set();将事件情形设置为平息意况,允许贰个或四个等待线程继续,再次来到值提醒操作是还是不是成功。

注:Semaphore类是SemaphoreSlim类的老版本,该版本接纳纯粹的水源时间(kernel-time)情势。

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

马努alReset伊芙ntSlim:不可使用于跨进度的共同。

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

某1财富或财富池的线程数。关于它的分量级demo,笔者的上三个多级有示范,你也足以知晓为Countdown伊芙nt是
塞马phoreSlim的效益加

重要成员:

 

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

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 }

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

   
 那种利用复信号状态的3头基元分外适合在动态的fork,join的风貌,它接纳“频域信号计数”的法子,就比如那样,1个麻将桌只可以包容3个人打麻将,借使后来的人也想搓壹把碰碰运气,那么他必须等待直到麻将桌上的人走掉1人。好,那正是回顾的时域信号计数机制,从技术角度上的话它是概念了最多能够进入第一代码的线程数。

 

三)public bool
Set();将事件情形设置为结束情状,允许一个或多少个等待线程继续,返回值提示操作是不是成功。

   
 但是Countdown伊夫nt更牛X之处在于大家得以动态的更改“实信号计数”的分寸,比如1会儿可见容纳八个线程,一下又5个,一下又13个,那样做有啥样利益吗?比如一个职分急需加载一w条数据,那么恐怕出现那种情景。

金沙注册送58 11

四)public void Wait();阻止当前线程,直到设置了现阶段 马努alReset伊夫ntSlim
甘休。

例如:

同一,防止死锁的景况,我们要求知道”超时和打消标记“的消除方案,像SemaphoreSlim那种定死的”线程请求范围“,其实是下落了扩充性,

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

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

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

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

加载Product表:    产品表数据绝相比较较多,计算之后必要开九个task。

 

5.Semaphore与SemaphoreSlim

加载order表:       由于自家的网址订单拉长,计算之后须求开十个task。

三: ManualResetEventSlim

Semaphore:可完结跨进程或AppDomain的壹起,可使用WaitHandle操作递减时限信号量的计数。

金沙注册送58 12金沙注册送58 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

用轻量级的本子会具备更加好的习性,原理大致就像是此,上边举个小例子。

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

大家看看有八个首要格局: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 }

三)public virtual bool WaitOne(); 阻止当前线程,直到近期System.Threading.WaitHandle 收到能量信号。 要是当前实例收到复信号,则为 true。
假若当前实例永远收不到信号,则
System.Threading.WaitHandle.WaitOne(System.Int3二,System.Boolean)永不再次来到。

注:如若调用Signal()未有到达钦定的次数,那么Wait()将一向等待,请确认保证使用种种线程达成后都要调用Signal方法。

 

注意:

 

金沙注册送58 14

选择完Semaphore立刻调用Dispose()方法释放能源。

 

塞马phoreSlim:不可达成跨进度或AppDomain的共同,不可使用WaitHandle操作递减复信号量的计数。

根本成员:

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

贰)public int CurrentCount { get; } 获取将允许进入
System.Threading.SemaphoreSlim 的线程的多少。

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

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

5)public WaitHandle AvailableWaitHandle { get;
}重临1个可用于在频限信号量上等待的 System.Threading.WaitHandle。

注意:

动用完SemaphoreSlim登时调用Dispose()方法释放能源。

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

重视成员:

一)public void Enter(ref bool lockTaken);
采纳可信赖的秘诀获得锁,这样,尽管在艺术调用中发出很是的情事下,都能选择可信赖的措施检查
lockTaken 以鲜明是否已获取锁。

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

说明:

一)不要将SpinLock评释为只读字段。

二)确定保障每一回职责完毕后都放出锁。

7.SpinWait:基于自旋的守候

首要成员:

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

二)public static bool SpinUntil(Func<bool> condition, int
millisecondsTimeout);在钦命条件获得满足或钦赐超时过期此前自旋。

说明:

一)适用意况:等待某些条件知足急需的时间相当短,并且不期望发生昂贵的上下文切换。

二)内部存储器成本十分的小。其是二个结构体,不会爆发不供给的内部存款和储蓄器开销。

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

8.Look:互斥锁

说明:

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

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

三)不要对值类型使用Lock

四)制止锁定类的表面对象,防止跨成员或类的边际获得和假释八个锁,制止获得锁的时候调用未知代码。

9.Monitor

重要成员:

一)public static void Enter(object obj, ref bool
lockTaken);获取钦点对象上的排他锁,并活动安装三个值,提醒是还是不是拿走了该锁。

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

三)public static void TryEnter(object obj, int millisecondsTimeout, ref
bool
lockTaken);在钦命的阿秒数中,尝试得到钦定对象上的排他锁,并机关安装一个值,提示是或不是拿走了该锁。

说明:

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

2)幸免锁定类的表面对象,幸免跨成员或类的边界获得和刑释一个锁,制止拿到锁的时候调用未知代码。

10.volatile修饰符

作用:

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

注意:

壹)能够将那一个修饰符用于类和struct的字段,但无法宣称使用volatile关键字的有的变量。

二)Volatile可修饰的档次为:整型,bool,带有整型的枚举,引用类型,推到为引用类型的泛型类型,不安全上下文中的指针类型以及代表指针只怕句柄的平台相关品种。

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

一言九鼎成员:

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

二)public static int Add(ref int location一, int value);对七个 三十八人整数举办求和并用和替换第3个整数,上述操作作为二个原子操作完毕。

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

四)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地图