Async 동기화 기원 구축, Part 5 AsyncSemaphore

6302 단어
전송문: 비동기 프로그래밍 시리즈 디렉터리...
요즘 공부하고 있어요.NET4.5 병렬 작업의 사용에 관하여.'병렬 작업' 은 이전 버전과 유사한 동기화 메커니즘을 보여 주지 않습니다. 이벤트 대기 핸들, 신호량, lock, Reader Writer Lock... 등 동기화 기원 대상을 보여 주지 않지만, 우리는 시내를 따라 프로그래밍 습관을 나타낼 수 있습니다. 그러면 이 일련의 번역은 '병렬 작업' 에 동기화 기원 대상을 봉인하는 것입니다.번역 리소스 Async 및 Await에 대한 FAQ
1. Async 동기화 기원 구축, Part 1 AsyncManualResetEvent
2. Async 동기화 기원 구축, Part 2 AsyncAutoResetEvent
3. Async 동기화 기원 구축, Part 3 AsyncCountdown Event
4. Async 동기화 기원 구축, Part 4 AsyncBarrier
5. Async 동기화 기원 구축, Part 5 AsyncSemaphore
6. Async 동기화 기원 구축, Part 6 AsyncLock
7. Async 동기화 기원 구축, Part 7 AsyncReader WriterLock
 
원본: Async 동기화 기원을 구축합니다.rar
시작: Async 동기화 기원 구축, Part 5 AsyncSemaphore
이전 글에서 저는 AsyncManualReset Event, AsyncAutoReset Event, AsyncCountdown Event와 AsyncBarrier를 구축했습니다.이 글에서, 나는 AsyncSemaphore 클래스를 구축할 것이다.
Semaphore(신호량)는 널리 사용되고 있습니다.중요한 응용 프로그램 중 하나는 접근 제한 자원을 보호하기 위한 것이다.에 있습니다.NET에는 두 가지 신호량 유형이 있는데 그것이 바로 Semaphore(Win32 함수 봉인)와 Semaphore Slim(봉인 모니터가 실현한 경량판)이다.이제 간단한 Async 버전을 구축할 예정입니다. 구축할 대상 유형은 다음과 같습니다.
public class AsyncSemaphore
{ 
    public AsyncSemaphore(int initialCount); 
    public Task WaitAsync(); 
    public void Release(); 
}

우리는 AsyncAutoResetEvent 구성원과 거의 같은 구성원 변수가 필요합니다. 변수가 존재하는 역할도 유사합니다.단일 대기자를 깨울 수 있어야 하기 때문에TaskCompletionSource의 실례 대기열을 유지합니다.우리는 막히기 전에 얼마나 많은 대기자가 완성할 수 있는지 알 수 있도록 신호량의 현재 계수를 추적해야 한다.그리고 우리는 이미 완성된 Task를 다시 사용하기 위해 유지하는 효율적인 조치를 발견할 수 있습니다.
private readonly static Task s_completed = Task.FromResult(true); 
private readonly Queue>m_waiters
                          = new Queue>(); 
private int m_currentCount;

클래스의 구조 함수는 초기화 요청 계수일 뿐입니다.
public AsyncSemaphore(int initialCount) 
{ 
    if (initialCount< 0) 
        throw new ArgumentOutOfRangeException("initialCount"); 
    m_currentCount = initialCount; 
}

이제 Waitasync () 방법을 구축해 보겠습니다.이 방법에서 우리는 lock을 사용하여 모든 작업이 원자로 실행되고 Release () 방법과 동기화되는지 확인해야 한다.그리고 여기에는 두 가지 상황이 있다.현재 mcurrentCount은 0보다 크고semaphore 제한 한계에 도달하지 않았기 때문에 이 대기 작업은 즉시 완성될 수 있습니다.이러한 상황에서 우리는 현재 계수를 줄이고 캐시에서 이미 완성한 퀘스트s 를 되돌려줍니다completed (즉, 논쟁이 없는 상황에서 우리는 새로운TaskCompletionSource 실례를 만들 필요가 없습니다.)현재 카운트 mcurrentCount는 0입니다. 우리는 새로운TaskCompletionSource 실례를 대기열에 추가하고 실례에 대응하는Task를 호출자에게 되돌려줍니다.
        public Task WaitAsync()
        {
            lock (m_waiters)
            {
                if (m_currentCount > 0)
                {
                    --m_currentCount;
                    return s_completed;
                }
                else
                {
                    var waiter = new TaskCompletionSource();
                    m_waiters.Enqueue(waiter);
                    return waiter.Task;
                }
            }
        }

Release () 방법에서 대기열에 대기자가 있으면 대기열에서 대기자를 삭제하고 해당하는 TaskCompletionSource 실례를 완성합니다.대기자가 없으면 현재 계수 m 를 간단하게 증가합니다currentCount.여기서는 원자성을 유지하고 Waitasync () 방법과 동기화해야 하기 때문에 Release () 의 주체 코드는 다시 mwaiters 대기열에 자물쇠를 채웁니다.여기서 주의해야 할 중요한 것은 앞의 글에서TaskCompletionSource의 [Try]Set*() 시리즈 방법을 토론했고TaskCompletionSource에 대응하는Task를 동기화 호출의 일부로 운행할 수 있도록 했다.만약 우리가 lock 내부에서 SetResilt () 를 호출한다면, Task의 동기화가 계속되는 운행은 장시간 lock을 가지고 있을 것입니다.따라서 lock을 해제한 후 Task의 [Try] Set* () 시리즈 방법을 사용하여 작업을 완료합니다.
        public void Release()
        {
            TaskCompletionSource toRelease = null;
            lock (m_waiters)
            {
                if (m_waiters.Count > 0)
                    toRelease = m_waiters.Dequeue();
                else
                    ++m_currentCount;
            }
            if (toRelease != null)
                toRelease.SetResult(true);
        }

 
이것이 바로 이 절에서 말하고자 하는 AsyncSemaphore이다.
전체 소스는 다음과 같습니다.
    public class AsyncSemaphore
    {
        //  Task 
        private readonly static Task s_completed = Task.FromResult(true);
        private readonly Queue> m_waiters
                                    = new Queue>();
        //  , 
        private int m_currentCount;

        public AsyncSemaphore(int initialCount)
        {
            if (initialCount < 0) 
                throw new ArgumentOutOfRangeException("initialCount");
            m_currentCount = initialCount;
        }

        public Task WaitAsync()
        {
            lock (m_waiters)
            {
                if (m_currentCount > 0)
                {
                    --m_currentCount;
                    return s_completed;
                }
                else
                {
                    var waiter = new TaskCompletionSource();
                    m_waiters.Enqueue(waiter);
                    return waiter.Task;
                }
            }
        }

        public void Release()
        {
            TaskCompletionSource toRelease = null;
            lock (m_waiters)
            {
                if (m_waiters.Count > 0)
                    toRelease = m_waiters.Dequeue();
                else
                    ++m_currentCount;
            }
            if (toRelease != null)
                toRelease.SetResult(true);
        }
    }

다음 절에서는 AsyncSemaphore를 사용하여 하나의 작용역 상호 배척 잠금 메커니즘을 실현하는 방법을 볼 것이다.
                                                                                                                
권장 읽기:
비동기 프로그래밍: 동기화 기원 대상 (위)
비동기 프로그래밍: 동기화 기원 대상 (하)
 
시청해 주셔서 감사합니다..
원문: Building Async Coordination Primitives, Part 5: AsyncSemaphore
작성자: Stephen Toub – MSFT

좋은 웹페이지 즐겨찾기