2010-08-11 2 views
22

나는 현재 그물에서 발견 된 새로운 System.Threading.Tasks 기능을 사용하여 새 구현 일부 홈 구운 작업 기능을 대체하고 4System.Threading.Tasks.Task이 완료 통지를 얻는 방법

나는 약간의 문제가 있지만, 몇 가지 해결책을 생각할 수는 있지만 일반적으로 최선의 방법을 제안하고, 어딘가에 속임수가 없다면 조언을 듣고 싶습니다.

내가 원하는 것은 임의의 프로세스가 작업을 시작할 수 있지만 계속 수행하고 작업이 끝날 때까지 기다리지 않는 것입니다. 문제는 아니지만 작업 결과로 무언가를해야 할 때 가장 좋은 방법이라고 확신하지는 않습니다.

필자가 보았던 모든 예제는 작업이 완료 될 때까지 또는 작업의 결과 매개 변수를 참조 할 때까지 Wait()를 사용합니다. 이 두 가지 모두 내가 원하지 않는 작업을 시작한 스레드를 차단합니다.

내가 생각 한 일부 솔루션 : 새로운 스레드를 생성하고 그에 작업을 시작, 새로운 스레드를 차단하는 대기() 또는 .Result를 사용하고 호출자에게 결과를 동기화

  1. 은 어쨌든, 아마도 IsCompleted 작업에 폴링을 할 수 있습니다.

  2. 실행하고 싶은 작업이 완료된 후에 시작할 수있는 '완료 완료'작업이 있습니다. 그러면 실행하려고하는 작업이 정적 이벤트 나 다른 것을 발생시킵니다.

  3. 대리인을 작업 입력에 전달하고 해당 작업을 호출하여 작업이 완료되었음을 알립니다.

내가 생각하는 나 장점과 단점 모두에게 있지만 특히에 작업을 시작하기 위해 명시 적으로 새로운 스레드를 만들 필요의 아이디어를 좋아하지 않아 수있을 때를 사용하는 목적의 하나 첫 번째 작업 클래스는 직접 스레드 사용을 추상화하는 것입니다.

가장 좋은 방법에 대한 의견이 있으십니까? 나는 간단한 것을 놓치고 있습니까? 'Completed'이벤트가 너무 많아서 물어볼 수 없습니까? :) (일이없는 이유를 확실히 좋은 이유가있다!)

+0

호기심에서 벗어나서 BackgroundWorker를 사용하지 않으시겠습니까? 작업 완료 및 취소 알림이 있습니다. – Robaticus

+1

'Task'가 우리와 함께있을 때'BackgroundWorker'는 더 이상 필요하지 않습니다. BGW는'SynchronizationContext'를 필요로했습니다. 이것은'Task' (선택 사항) (더 큰 병렬 처리를 가능하게합니다)입니다. –

답변

26

I 의심 당신이 Task.ContinueWith (또는 Task<T>.ContinueWith)를 찾고 있습니다. 이것은 기본적으로 "이 작업을 마쳤 으면이 작업을 실행하십시오." 그러나이를 제어하기 위해 지정할 수있는 다양한 옵션이 있습니다.

MSDN은 "How to: Chain Multiple Tasks With Continuations""Continuation Tasks"에 대해 더 자세히 설명합니다.

+0

네, 이해 합니다만, 태스크의 순서가 Task.Wait() (및 따라서 블로킹)를 호출하지 않고 완료되면 태스크를 시작한 스레드에서 알 수있는 문제는 해결되지 않습니다. (위와 같이) 내가 생각한 한 가지 접근 방법은 Task.ContinueWith를 사용하여 이해 관계자가 가입 할 수있는 이벤트를 발생시키는 작업을 연결하는 것이 었습니다. 이것은 원래 작업을 원자 적으로 유지합니다. –

+1

@bwilliams : 왜 작업을 노출하지 않고 관심있는 사람들이 'Task.ContinueWith'를 호출 할 수 있습니까? 나는 그것이 어떤 방식으로 보이지 않는지 * 작업이 완료되었을 때를 아는 문제를 해결하지 않는다. "차단이 끝나면 다시 전화 해."라고하는 비 차단 호출입니다. –

+1

(작업 자체를 노출하는 대신 내부적으로 'ContinueWith'를 호출하는 자체 메서드를 제공 할 수 있습니다. 실제로는 똑같습니다.) –

4

task continuation을 적용 할 수 있습니다.

또는 TaskIAsyncResult를 구현, 그래서 당신은 standard approaches for that interface (차단, 폴링, 또는 WaitHandle에서 대기)를 사용할 수 있습니다.

+0

작업 계속 주제에 대한 존 Skeet의 게시물 아래 내 의견을 참조하십시오. 차단 및 폴링 작업을 시작한 원래 스레드를 응답 성있게 유지하기 위해 다른 스레드를 시작해야한다는 것을 의미하는 것은 좋지 않습니다. WaitHandle을 사용할 수 있음을 알았지 만, 문서에서 선호하는 방법은 Task.Wait()를 사용하는 것이라고합니다. 그건 내가 원하는 걸하지 않는 것처럼 말했어. 아마도 WaitHandle이 나에게 최고 다. –

4

현대 C#에서는 더 이상 ContinueWith()을 명시 적으로 호출 할 필요가 없습니다. 원래 수용된 대답의 대안은 Task이 완료 될 때 Task이라는 await의 메서드를 만들고 Task이 원하는대로 수행하는 것입니다.

예를 들어 Task이 완료되면 TaskCompleted이라는 이벤트를 발생 시키려고한다고 가정합니다. 다음과 같은 메소드를 작성하십시오 :

async Task RaiseEventWhenTaskCompleted(Task task) 
{ 
    await task; 
    TaskCompleted?.Invoke(this, EventArgs.Empty); 
} 

"대기"하려면 위의 메소드를 호출하십시오. 위의 메서드 또는 위의 메서드에서 반환 된 Task을 결국 관찰 할 일부 코드에서 원하는대로 예외 처리를 추가합니다.

관련 문제