Async 동기화 기원 구축, Part 2 AsyncAutoResetEvent

5928 단어
전송문: 비동기 프로그래밍 시리즈 디렉터리...
요즘 공부하고 있어요.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 2 AsyncAutoResetEvent
전편에서는 async 버전의 ManualResetEvent를 구축했습니다.이제 AutoReset Event의 async 버전을 구축합니다.
ManualResetEvent 대상은 Set() 방법을 호출할 때 ManualResetEvent가 신호 상태로 전환되고 Reset() 방법을 호출하여 무신호 상태로 초기화할 때까지 이 신호를 가지고 있으며 Reset()를 호출하여 무신호 상태로 초기화하면 다음 WaitOne() 대기 신호가 발생합니다.이에 비해 AutoResetEvent도 Set() 방법을 호출할 때 신호를 받았지만 WaitOne()을 호출한 후 자동으로 무신호 상태로 재설정되었다.예를 들어 ManualResetEvent에 4개의 대기 라인이 있다면, 그 중 하나가 set () 방법을 호출하면 4개의 대기 라인이 완성될 것이다.이에 비해 AutoReset Event에 4개의 대기 라인이 있다면 그 중 한 라인이 set () 방법을 호출한 후에 그 중 한 라인만 신호를 받고 다른 3개의WaitHandle은 여전히 무신호 상태이다. (주의해야 할 것은 AutoReset Event는 종적 신호를 따라가지 못하게 할 수 있다. 예를 들어 처음에는 라인 대기 없이 이벤트가 set () 신호를 두 번 수신한 다음에 두 라인이 다시 이벤트에서 신호를 기다린다.이때 그중 하나만 완성 대기 - 예시 m 참조signaled 변수의 실현).
이것은 우리가 구축할 목표 유형이다.
public class AsyncAutoResetEvent
{ 
    public Task WaitAsync(); 
    public void Set(); 
}

우선 구성원이 필요합니다(eg:TaskCompletionSource).이전 편의 AsyncManual Reset Event, 이벤트에 대한 알림이 현재의 모든 기다림을 깨우치기 때문에 Task Completion Source 실례만 있으면 됩니다.그러나 AsyncAuto Reset Event는 다르기 때문에 우리는 서로 다른 기다림을 구별해야 한다. 만약에 여러 개의 라인이 기다린다면 한 신호가 도착하면 한 개의 기다림만 깨울 수 있기 때문이다.따라서 TaskCompletionSource 실례 집합이 필요합니다.또한 신호가 도착했을 때 대기자가 없을 수도 있기 때문에 bool 변수를 사용하여 추적해야 합니다.마지막으로, 완료된 Task 를 다시 사용하여 성능을 향상시킬 수 있는 경우도 있기 때문에 다음 중 하나를 참조하도록 설계되었습니다.
private readonly static Task s_completed = Task.FromResult(true); 
private readonly Queue m_waits
                    = new Queue(); 
private bool m_signaled;

이제 Waitasync()라는 이름을 가진 방법을 구현합니다.Waitasync()를 호출할 때 msignaled는true입니다. 완성된 s 로 바로 돌아갑니다.completed, 이 대기 호출 소비 이 신호 때문에 msignaled가false로 재설정되었습니다.하면, 만약, 만약...signaled는false입니다.TaskCompletionSource 실례를 m 에 삽입합니다waits 대기열에서 인스턴스에 해당하는 Task 를 반환합니다.이 Task 는 Task 의 Set () 메서드를 호출하고 대기자를 깨울 때까지 Task 작업이 지연됩니다.그러나 주의해야 할 것은, 여기는 여러 조작이 집행하는 원자성을 유지해야 하기 때문에, 나는 m 에 대해동기화를 확보하기 위해 waits 대기열을 잠그십시오.
public Task WaitAsync() 
{ 
    lock (m_waits) 
    { 
        if (m_signaled) 
        { 
            m_signaled = false; 
            returns_completed; 
        } 
        else
        { 
            var tcs = new TaskCompletionSource(); 
            m_waits.Enqueue(tcs); 
            return tcs.Task; 
        } 
    } 
}

그런 다음 Set () 방법을 구현합니다.Set () 메서드는 m 를 먼저 확인합니다.waits 대기열에 대기자가 있는지 여부입니다.있으면 대기열에서 TaskCompletionSource를 꺼내서 완성합니다.하면, 만약, 만약...waits 대기열이 비어 있으면 m 를 간단하게signaled가true로 설정되었습니다.여기서는 원자성을 유지하고 Waitasync () 방법과 동기화해야 하기 때문에 set () 의 주체 코드는 다시 mwaits 대기열에 자물쇠를 채웁니다.여기서 주의해야 할 중요한 것은 앞의 글에서TaskCompletionSource의 [Try]Set*() 시리즈 방법을 토론했고TaskCompletionSource에 대응하는Task를 동기화 호출의 일부로 운행할 수 있도록 했다.만약 우리가 lock 내부에서 SetResilt () 를 호출한다면, Task의 동기화가 계속되는 운행은 장시간 lock을 가지고 있을 것입니다.따라서 lock을 해제한 후 Task의 [Try] Set* () 시리즈 방법을 사용하여 작업을 완료합니다.
public void Set() 
{ 
    TaskCompletionSource toRelease = null
    lock (m_waits)
    { 
        if (m_waits.Count> 0) 
            toRelease = m_waits.Dequeue(); 
        else if (!m_signaled) 
            m_signaled = true; 
    } 
    if (toRelease != null)  
        toRelease.SetResult(true); 
}

이 섹션에서 설명하고자 하는 AsyncAutoResetEvent 입니다.
전체 소스는 다음과 같습니다.
    public class AsyncAutoResetEvent
    {
        //   Task, 
        private readonly static Task s_completed = Task.FromResult(true);
        //  
        private readonly Queue> m_waits = new Queue>();
        //      , AsyncAutoResetEvent 
        private bool m_signaled;

        public Task WaitAsync()
        {
            lock (m_waits)
            {
                if (m_signaled)
                {
                    m_signaled = false;
                    return s_completed;
                }
                else
                {
                    var tcs = new TaskCompletionSource();
                    m_waits.Enqueue(tcs);
                    return tcs.Task;
                }
            }
        }

        public void Set()
        {
            TaskCompletionSource toRelease = null;
            lock (m_waits)
            {
                if (m_waits.Count > 0)
                    toRelease = m_waits.Dequeue();
                else if (!m_signaled)
                    m_signaled = true;
            }
            if (toRelease != null)
                toRelease.SetResult(true);
        }
    }

다음 절에서는 async 버전의 Countdown 이벤트를 실현할 것입니다.
 
 
권장 읽기:
비동기 프로그래밍: 동기화 기원 대상 (위)
비동기 프로그래밍: 동기화 기원 대상 (하)
 
시청해 주셔서 감사합니다..
원문: Building Async Coordination Primitives, Part 2: AsyncAutoReset Event
작성자: Stephen Toub – MSFT

좋은 웹페이지 즐겨찾기