2012-07-24 2 views
0

최근에 Jon Skeet’s blog에서 Eduasync serial을 읽었습니다. part 7을 읽었을 때 한 가지 질문으로 인해 C#이 statemachine을 생성하는 것이 드문 경우에 제대로 작동하지 않을 것이라고 생각했습니다. 코드가 깊습니다 (이 코드는 Jon Skeet의 Eduasync 파트 7에서 나온 것입니다).비동기 생성 된 StateMachine에서 MoveNext에 대해 원자 적으로 의미가 있습니까?

public void MoveNext() 
{ 
    int result; 
    try 
    { // doFinallyBodies is never used 
     bool doFinallyBodies = true; 
     if (state != 1) 
     { 
      if (state != -1) 
      { 
       task = Task<int>.Factory.StartNew(() => 5); 
       awaiter = task.GetAwaiter(); 
       // In a rare case, in this moment the task still has not completed, 
       // so return false IsCompleted 
       if (awaiter.IsCompleted) 
       { 
        goto Label_GetResult; 
       } 
       state = 1; 
       // The task just completed before OnCompleted, 
       // but in this moment we haven't call the OnCompleted yet, 
       // so the task's ContinueWith is nothing the task will complete 
       // without ContinueWith and we will never get back to this StateMachine again. 
       doFinallyBodies = false; 
       awaiter.OnCompleted(moveNextDelegate); 
      } 
      return; 
     } 
     state = 0; 
     Label_GetResult: 
     int awaitResult = awaiter.GetResult(); 
     awaiter = new TaskAwaiter<int>(); 
     result = awaitResult; 
    } 
    catch (Exception e) 
    { 
     state = -1; 
     builder.SetException(e); 
     return; 
    } 
    state = -1; 
    builder.SetResult(result); 
} 

public struct TaskAwaiter<T> 
{ 
    private readonly Task<T> task; 

    internal TaskAwaiter(Task<T> task) 
    { 
     this.task = task; 
    } 

    public bool IsCompleted { get { return task.IsCompleted; } } 

    public void OnCompleted(Action action) 
    { 
     SynchronizationContext context = SynchronizationContext.Current; 
     TaskScheduler scheduler = context == null ? TaskScheduler.Current 
      : TaskScheduler.FromCurrentSynchronizationContext(); 
     task.ContinueWith(ignored => action(), scheduler); 
    } 

    public T GetResult() 
    { 
     return task.Result; 
    } 
} 

이게 문제가 될 수 있다고 생각하십니까? 내가 제대로 이해를 확인하기 위해

답변

1

, 난 당신이 더 자세히 기대하고 생각하는 이벤트의 순서를 설명 할 것이다 :

비동기 작업을하는 것,
  • IsCompleted
  • 이 선택되어 시작
    1. 작업이 차례로 ContinueWith()를 호출하는 동작은
    2. OnCompleted()가 호출 완료 아직
    3. 완료되지 않았기 때문에, false을 반환하지만, 때문에 Task 이미 계속 내가이 올바른, 당신의 실수 단계 Task의 저자는이 경쟁 조건을 알고 있었기 때문이다 (4)에 도착하면

    을 실행하지 않으며, 결코, 완료 그래서 당신은에 ContinueWith()를 호출하는 경우 이미 완료된 Task 일 경우, 연속 번호는 즉시입니다. 따라서 상태 시스템은이 상황에서도 올바르게 작동합니다.

    불행히도 the documentation for ContinueWith()은 이에 대해 명확하지 않습니다 (이 예약되지 않을 때이 예약 될 때 설명되지만, 예정된 경우는 그렇지 않습니다).

    +0

    예, 정확하게 묻고 싶습니다. 답장을 보내 주셔서 감사합니다. 그런데 MSDN 문서를 제외하고 ContinueWith()가 "immediatelly"로 예약 될 것입니다. – ivenxu

    +0

    그건 단지'Task'가 현재'TaskScheduler'에 추가된다는 것을 의미합니다. 그런 다음 스케줄러가 실행됩니다. 네가 물어 본거야? – svick

    관련 문제