2017-12-30 12 views
0

대부분의 경우 비동기 코드 차단이 승인되지 않는다는 것을 알고 있습니다.Thread.Sleep() 및 Task.Yield()로 비동기로 차단

그러나 WPF 응용 프로그램에서 백그라운드 작업을 실행하고 있습니다. 사용자가 창을 닫으면이 작업을 취소하고 취소 및 후속 정리가 완료 될 때까지 창의 닫기가 지연됩니다. 그 동안 더 이상의 사용자 입력을 차단해야합니다.

ViewModel.cs : 시도 & 검색을 조금 후

, 나는 다음과 같은 코드를 내놓았다

async void RunTaskAsync() 
{ 
    _cancelTknSource = new CancellationTokenSource(); 
    try { 
     await Task.Run(/*...long running calculation...*/, _cancelTknSource.Token); 
    } 
    catch (OperationCanceledException) { } 
    finally { 
     /*...cleanup...*/ 
     _cancelTknSource.Dispose(); 
     _cancelTknSource = null;    
    } 
} 

async Task CancelAsync() 
{ 
    _cancelTknSource?.Cancel(); 
    while (_cancelTknSource != null) { 
     Thread.Sleep(10); 
     await Task.Yield(); //prevents dead-lock 
    } 
} 

Window.xaml.cs :

async void Window_Closing(object sender, CancelEventArgs e) 
{ 
    e.Cancel = true; 
    await DataContext.CancelAsync(); 
    Close(); 
} 

(모든 이러한 메서드는 UI 스레드에서 호출됩니다.

이 좋은 방법입니까? 그렇지 않은 경우 대체 방법은 무엇입니까?

+2

안녕하십니까. StackExchange 네트워크에서이 질문이 형제 사이트 _Code Review_ (귀하의 질문이 아닌 디자인이기 때문에)에서 더 잘 질문 할 수 있을지 궁금합니다. 행운을 빌어 요. – MickyD

+1

Task.Yield()는 교착 상태를 수정하지 않고 UI 스레드가 더 이상 알림을 처리 할 수 ​​없다는 근본적인 문제를 해결하지 못합니다. WPF에 대한 조언은 기본적으로 Winforms와 다릅니다 (https://stackoverflow.com/a/1732361/17034). –

+0

"Task.Run을 기다립니다 (/ * ... 장기 실행 계산 ... * /, _ cancelTknSource.Token);" 이 작업을 기다리고 있다면. 토큰의 요점은 무엇입니까? – efekctive

답변

0

오류 처리 및 정리 (예 : _cancelTknSource 및 _runningTask를 null로 설정)가 없으면 다음 코드가 수행해야합니다. 그러나 여전히 Window_Closing과 실제 윈도우 닫기 사이의 일부 UI 기능을 차단해야합니다.

async void RunTaskAsync() 
{ 
    using(_cancelTknSource = new CancellationTokenSource()) 
    { 
     _runningTask =Task.Run(/*...long running calculation...*/, _cancelTknSource.Token); 
     await _runningTask; 
    } 
} 

Task CancelAsync() 
{ 
    _cancelTknSource?.Cancel(); 
    return _runningTask; 
} 
Window.xaml.cs: 

async void Window_Closing(object sender, CancelEventArgs e) 
{ 
    e.Cancel = true; 
    await DataContext.CancelAsync(); 
    Close(); 
} 
+0

내게는 Close()가 RunTaskAsync의 나머지 부분 이전 또는 이후에 (내 정리를 수행 할 곳) using 블록 이후에 실행되는지 여부가 명확하지 않습니다. 두 방법 모두 동일한 작업을 기다리고 있기 때문입니다 ... 아마도 더 좋을 수도 있습니다. RunTaskAsync()를 void에서 Task로 변경하고 _runningTask에 저장하십시오 (Peter가 제안한대로) – Cornix

+0

@Cornix는 동일한 작업에서 여러 개의'await'에 대해 [이미 실행 중이거나 실행중인 작업을 기다리는 경우 어떻게됩니까?] (https : //stackoverflow.com/a/32434481/585968) – MickyD