2013-05-27 2 views
7

, 작업이 완료 될 때까지 자식 작업을 기다리는 부모 작업을 의미 TaskCreationOptions.AttachedToParent를 사용하여 두 개의 자식 작업을 만듭니다. 왜 부모 작업이 올바른 값 [102] 반환하지 않습니다 -반환 값은 아래의 코드에서

질문은? 먼저 반환 값을 결정한 다음 하위 작업이 완료 될 때까지 대기합니까? 그렇다면 부모 - 자식 관계를 생성하는 요점은 무엇입니까?

void Main() 
{ 
Console.WriteLine ("Main start."); 
int i = 100; 

Task<int> t1 = new Task<int>(()=> 
{ 
    Console.WriteLine ("In parent start"); 
    Task c1 = Task.Factory.StartNew(() => { 
     Thread.Sleep(1000); 
     Interlocked.Increment(ref i); 
     Console.WriteLine ("In child 1:" + i); 
    }, TaskCreationOptions.AttachedToParent); 

    Task c2 = Task.Factory.StartNew(() => { 
     Thread.Sleep(2000); 
     Interlocked.Increment(ref i);   
     Console.WriteLine ("In child 2:" + i); 
    }, TaskCreationOptions.AttachedToParent); 

    Console.WriteLine ("In parent end"); 
    return i; 
}); 

t1.Start(); 
Console.WriteLine ("Calling Result."); 
Console.WriteLine (t1.Result); 
Console.WriteLine ("Main end."); 
} 

출력 :

Main start. 
Calling Result. 
In parent start 
In parent end 
In child 1:101 
In child 2:102 
100 
Main end. 

답변

5

문제는 별도의 작업으로 c1c2를 생성하지만 c1c2i을 증가하기 전에 t1에서 즉시 i를 반환 할 것입니다.

따라서이 시점에서 t1의 반환 값이 캡처되고 여전히 100입니다.

당신이 언급 한 바와 같이,이 배열에 대한 부모/자식 관계에서 많은 지점이 아니다; 많은 경우가 있습니다. 을 의미합니다.

일반적으로 부모 작업은 자식 작업이 완료 될 때까지 완료되지 않지만 부모 작업이 값을 반환하기 전에 자식 작업을 기다려야하는 경우에는이를 수행 할 수 없습니다. 이. 물론

, 당신은 단지 return i; 전에

Task.WaitAll(c1, c2); 

를 추가하여 문제를 해결할 수 있습니다. 당신이 묻는 것이 아니라는 것을 압니다 만, 어쨌든 그것을 지적하고 싶었습니다.

+0

예 대기 중 및 반환 값은 서로 다르지만 반환 값을 결정하기 전에 기다리지 않는 것이 좋습니다. 이것이 TPL의 버그 일 수 있다고 생각하십니까? – thewpfguy

+0

@thewpfguy 아니요, 분명히 버그는 아닙니다. 첫 번째 작업을 시작한 작업이 첫 번째 작업의 반환 값에 액세스하기 전에 종료 된 경우 작업 결과가 캐싱된다는 것은 자연스러운 결과입니다. –

-1

으로 이미이 증가되기 전에 i 값을 반환했다. 이런 방식으로 코드를 변경하면이 기대 값 (102)을 반환 :

void Main() 
{ 
    Console.WriteLine ("Main start."); 
    int i = 100; 

    Task<int> t1 = new Task<int>(()=> 
    { 


    Console.WriteLine ("In parent start"); 
    Task c1 = Task.Factory.StartNew(() => { 
     Interlocked.Increment(ref i); 
     Console.WriteLine ("In child 1:" + i); 
    }, TaskCreationOptions.AttachedToParent); 

    Thread.Sleep(1000); 

    Task c2 = Task.Factory.StartNew(() => { 
     Interlocked.Increment(ref i);   
     Console.WriteLine ("In child 2:" + i); 
    }, TaskCreationOptions.AttachedToParent); 

    Thread.Sleep(1000); 

    Console.WriteLine ("In parent end"); 
    return i; 
}); 

t1.Start(); 
Console.WriteLine ("Calling Result."); 
Console.WriteLine (t1.Result); 
Console.WriteLine ("Main end."); 
} 

내가 단순히 부모 작업에 자식 작업에서 (1000)에 Thread.sleep를 꺼내입니다했다. 결과는 변수가 증가 된 후에 반환됩니다.

+2

이것은 끔찍한 해답입니다. 긴 작업을 시뮬레이션하기 위해 수면이 하위 작업에 추가되었습니다. 이들을 주요 업무로 이동시키는 것은 불쌍한 사람의 동기화 메커니즘입니다. 아이 taks가 완료하는 데 1000ms 이상 걸리지 않는 한 확실히 작동합니다. 우리가 .NET에서 데이터를 동기화 할 수있는 많은 방법이 있다는 것을 감안할 때 수면을 사용하면 결코 사용할 수없는 최악의 솔루션입니다 – Pako

+0

@Pako 저는 동의합니다.하지만 저는 int 변수가 왜 그렇지 않은지 지적하고 싶었습니다. 두 가지 작업이 끝나면 업데이트됩니다. – codingadventures